PKCS10CertificationRequestBuilder создает недействительный PKCS10CertificationRequest в org.bouncycastle.pkcs
Я пытаюсь использовать Spongy Castle (v1.47) для создания запроса на сертификацию PKCS10. Spongy Castle ведет себя точно так же, как Bouncy Castle, но больше подходит для портирования на Android.
Старый (ограниченный) способ, описанный Дэвидом Хуком в главе 6 "Начало криптографии с Java" в главе 6, прекрасно работает:
package chapter6;
import java.io.OutputStreamWriter;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.Security;
import java.util.Vector;
import javax.security.auth.x500.X500Principal;
import org.spongycastle.asn1.DEROctetString;
import org.spongycastle.asn1.DERSet;
import org.spongycastle.asn1.pkcs.Attribute;
import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.spongycastle.asn1.x509.GeneralName;
import org.spongycastle.asn1.x509.GeneralNames;
import org.spongycastle.asn1.x509.X509Extension;
import org.spongycastle.asn1.x509.X509Extensions;
import org.spongycastle.jce.PKCS10CertificationRequest;
import org.spongycastle.openssl.PEMWriter;
import org.spongycastle.jce.provider.BouncyCastleProvider;
/**
* Generation of a basic PKCS #10 request with an extension.
*/
public class PKCS10ExtensionExample {
static {
BouncyCastleProvider prov = new org.spongycastle.jce.provider.BouncyCastleProvider();
Security.addProvider(prov);
}
public static PKCS10CertificationRequest generateRequest( KeyPair pair) throws Exception {
// create a SubjectAlternativeName extension value
GeneralNames subjectAltName = new GeneralNames(new GeneralName(GeneralName.rfc822Name, "test@test.test"));
// create the extensions object and add it as an attribute
Vector oids = new Vector();
Vector values = new Vector();
oids.add(X509Extensions.SubjectAlternativeName);
values.add(new X509Extension(false, new DEROctetString(subjectAltName)));
X509Extensions extensions = new X509Extensions(oids, values);
Attribute attribute = new Attribute(PKCSObjectIdentifiers.pkcs_9_at_extensionRequest, new DERSet(extensions));
return new PKCS10CertificationRequest(
"SHA256withRSA",
new X500Principal("CN=Requested Test Certificate"),
pair.getPublic(),
new DERSet(attribute),
pair.getPrivate());
}
public static void main(String[] args) throws Exception {
// create the keys
KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", "SC");
kpGen.initialize(1024, Utils.createFixedRandom());
KeyPair pair = kpGen.generateKeyPair();
PKCS10CertificationRequest request = generateRequest(pair);
PEMWriter pemWrt = new PEMWriter(new OutputStreamWriter(System.out));
pemWrt.writeObject(request);
pemWrt.close();
}
}
Маленькая Java-программа выводит следующее:
-----BEGIN CERTIFICATE REQUEST-----
MIIBkDCB+gIBADAlMSMwIQYDVQQDExpSZXF1ZXN0ZWQgVGVzdCBDZXJ0aWZpY2F0
ZTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAm38mHcNo+YDhe1/XHRa1Cifj
EUwH6SQfqKQcY0sO4gGTVL/U5kBx/y0gIptrnGgUYgfwqptWoKHIqd4PGAuzHfwI
QrTfnYtLnN3dBdnOx/1mZuJ/fCD48H45sTVCcXbypxdwns2PZwgh1rt+jb7TJQii
5TteCLvzzb7FVb/Oc6MCAwEAAaAsMCoGCSqGSIb3DQEJDjEdMBswGQYDVR0RBBIw
EIEOdGVzdEB0ZXN0LnRlc3QwDQYJKoZIhvcNAQELBQADgYEAJexpAYF6RvbYGiNS
kyaF1H8TpDOHaAuIvS4G2Kqw9xXJHYEDiNsQxMc4gWdx6ZNDzc1JYqFBaEV+c/zt
pRPLTRxTi841tLBUAzX7eFQ5EtLwJrKLlHCMXxg3DwcrPjRwidcE87Nl/sOyeT4K
btCXzqpLtklJi/giBl/4L+lQunU=
-----END CERTIFICATE REQUEST-----
Проблема в том, что в то же время (книга 2005 года) большинство этих классов помечены как ограниченные. Новый способ создания запросов на подпись сертификатов - использование фабричных шаблонов:
package chapter6;
import java.io.OutputStreamWriter;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.Security;
import java.util.Vector;
import org.spongycastle.asn1.DERPrintableString;
import org.spongycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.spongycastle.asn1.x500.X500Name;
import org.spongycastle.asn1.x509.ExtendedKeyUsage;
import org.spongycastle.asn1.x509.KeyPurposeId;
import org.spongycastle.asn1.x509.KeyUsage;
import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
import org.spongycastle.asn1.x509.X509Extension;
import org.spongycastle.jce.provider.BouncyCastleProvider;
import org.spongycastle.openssl.PEMWriter;
import org.spongycastle.operator.ContentSigner;
import org.spongycastle.operator.ContentVerifierProvider;
import org.spongycastle.operator.jcajce.JcaContentSignerBuilder;
import org.spongycastle.operator.jcajce.JcaContentVerifierProviderBuilder;
import org.spongycastle.pkcs.PKCS10CertificationRequest;
import org.spongycastle.pkcs.PKCS10CertificationRequestBuilder;
/**
* Generation of a basic PKCS #10 request with an extension.
*/
public class PKCS10ExtensionExampleNew {
static {
BouncyCastleProvider prov = new org.spongycastle.jce.provider.BouncyCastleProvider();
Security.addProvider(prov);
}
public static PKCS10CertificationRequest generateRequest(KeyPair pair) throws Exception {
SubjectPublicKeyInfo publicKeyInfo = SubjectPublicKeyInfo.getInstance(pair.getPublic().getEncoded());
X500Name subject = new X500Name("CN=Requested Test Certificate");
PKCS10CertificationRequestBuilder certificationRequestBuilder = new PKCS10CertificationRequestBuilder(subject, publicKeyInfo);
certificationRequestBuilder.addAttribute(X509Extension.keyUsage,
new KeyUsage(KeyUsage.digitalSignature | KeyUsage.keyEncipherment | KeyUsage.dataEncipherment | KeyUsage.keyAgreement));
Vector<KeyPurposeId> ekUsages = new Vector<KeyPurposeId>();
ekUsages.add(KeyPurposeId.id_kp_clientAuth);
ekUsages.add(KeyPurposeId.id_kp_serverAuth);
certificationRequestBuilder.addAttribute(X509Extension.extendedKeyUsage, new ExtendedKeyUsage(ekUsages));
JcaContentSignerBuilder contentSignerBuilder = new JcaContentSignerBuilder("SHA1WithRSAEncryption");
contentSignerBuilder.setProvider("SC");
ContentSigner contentSigner = contentSignerBuilder.build(pair.getPrivate());
DERPrintableString password = new DERPrintableString("secret123");
certificationRequestBuilder.addAttribute(PKCSObjectIdentifiers.pkcs_9_at_challengePassword, password);
PKCS10CertificationRequest certificationRequest = certificationRequestBuilder.build(contentSigner);
JcaContentVerifierProviderBuilder contentVerifierProviderBuilder = new JcaContentVerifierProviderBuilder();
ContentVerifierProvider contentVerifierProvider = contentVerifierProviderBuilder.build(pair.getPublic());
System.out.println("isSignatureValid? " + certificationRequest.isSignatureValid(contentVerifierProvider));
System.out.println(certificationRequest.getSubject());
return certificationRequest;
}
public static void main(String[] args) throws Exception {
// create the keys
KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", "SC");
kpGen.initialize(1024, Utils.createFixedRandom());
KeyPair pair = kpGen.generateKeyPair();
PKCS10CertificationRequest request = generateRequest(pair);
PEMWriter pemWrt = new PEMWriter(new OutputStreamWriter(System.out));
pemWrt.writeObject(request);
pemWrt.close();
}
}
Запрос сертификата не собирается должным образом, так как он терпит неудачу при генерации PEM:
isSignatureValid? true
CN=Requested Test Certificate
Exception in thread "main" org.spongycastle.util.io.pem.PemGenerationException: unknown object passed - can't encode.
at org.spongycastle.openssl.MiscPEMGenerator.createPemObject(MiscPEMGenerator.java:208)
at org.spongycastle.openssl.MiscPEMGenerator.generate(MiscPEMGenerator.java:333)
at org.spongycastle.util.io.pem.PemWriter.writeObject(PemWriter.java:76)
at org.spongycastle.openssl.PEMWriter.writeObject(PEMWriter.java:45)
at be.boeboe.spongycastle.chapter6.PKCS10ExtensionExampleNew.main(PKCS10ExtensionExampleNew.java:71)
У кого-нибудь есть идеи, почему вторая попытка создать запрос не удалась? Я создал сертификаты X509V3Certificate как по старому, так и по новому способу, и у меня не было никаких проблем, но размещение этих отличий рядом с показанными здесь, не сделало меня мудрее.
Любая помощь приветствуется.
Boeboe