2013-09-05 4 views
6

Więc mój problem jest następujący,Prawidłowo tworząc nowy certyfikat z pośredniego certyfikatu przy użyciu bouny zamek

Zasadniczo chcę, aby utworzyć łańcuch certyfikatów używając nadmuchiwany zamek (jdk16 wersji 1.46). Jestem raczej nowy w odniesieniu do dmuchanego zamku i java.security w ogóle, więc jeśli moje podejście może być całkowicie błędne, ale w każdym razie to właśnie zrobiłem:

Do tej pory jestem w stanie stworzyć samopodpisany certyfikat, którego używam jako certyfikat główny. Odbywa się to za pomocą następującego kodu:

//-----create CA certificate with key 
KeyPair caPair = Signing.generateKeyPair("DSA", 1024, null, null); 

to w zasadzie tworzy parę kluczy, obie opcje są zerowe dla dostawcy i bezpieczny sposób losowy, w razie potrzeby.

Map<ASN1ObjectIdentifier, Entry<Boolean, DEREncodable>> caMap = new HashMap<ASN1ObjectIdentifier, Entry<Boolean, DEREncodable>>(); 
caMap.put(X509Extensions.BasicConstraints, new AbstractMap.SimpleEntry<Boolean, DEREncodable>(true, new BasicConstraints(true))); 

//------this creates the self signed certificate   
X509Certificate caCert = X509CertificateGenerator.generateX509Certificate(serial, "CN=CA", "CN=CA", start, end, "SHA1withDSA", caPair.getPrivate(), caPair.getPublic(), null, caMap); 

Spowoduje to utworzenie certyfikatu z dostarczonymi atrybutami.

  • seryjne = prostu bieżący czas w milisekundach
  • początek = takie same jak szeregowy zasadniczo (może mieć 1 lub 2 ms różnica)
  • końcowe = start + 2 dni

Mapa prostu dodaje podstawowe ograniczenie, aby ustawić certyfikat jako CA. Używam tutaj mapy, ponieważ chcę w razie potrzeby móc dodać dodatkowe rozszerzenia X509.

//-----save ca certificate in PEM format 
X509CertificateGenerator.savePemX509Certificate(caCert, caPair.getPrivate(), caWriter); 

Spowoduje to zapisanie certyfikatu i klucza prywatnego w pliku PEM za pomocą kreatora skaczkowego pisma kem.

Po tym plik zostanie wygenerowany i mogę zainstalować plik również (ja używam IE, a następnie zainstalować go za pośrednictwem Opcji internetowych jako zaufany CA. Certyfikat również okazał się ważny).

Następnie utworzyć certyfikat pośredni, z zastosowaniem kodu (uwagę powyższy kod znajduje się w takim samym zakresie, tak tych zmiennych są również dostępne)

KeyPair intermediatePair = Signing.generateKeyPair("DSA", 1024, null, null);  

Map<ASN1ObjectIdentifier, Entry<Boolean, DEREncodable>> intermediateMap = new HashMap<ASN1ObjectIdentifier, Entry<Boolean, DEREncodable>>(); 
intermediateMap.put(X509Extensions.AuthorityKeyIdentifier, new AbstractMap.SimpleEntry<Boolean, DEREncodable>(false, new AuthorityKeyIdentifierStructure(caCert))); 
intermediateMap.put(X509Extensions.SubjectKeyIdentifier, new AbstractMap.SimpleEntry<Boolean, DEREncodable>(false, new SubjectKeyIdentifierStructure(intermediatePair.getPublic()))); 

X509Certificate intermediateCert = X509CertificateGenerator.generateX509Certificate(serial.add(BigInteger.valueOf(1l)), "CN=intermediate", caCert.getSubjectX500Principal().toString(), start, end, "SHA1withDSA", caPair.getPrivate(), intermediatePair.getPublic(), null, intermediateMap); 

//-----save intermediate certificate in PEM format 
X509CertificateGenerator.savePemX509Certificate(intermediateCert, intermediatePair.getPrivate(), intermediateWriter); 

procedura jest Bascially takie same, jednak I dodać dodatkowe X509Extensions:

  • X509Extensions.AuthorityKeyIdentifier = oznacza certyfikat CA jako półproduktów rodzica
  • X509Extensions.SubjectKeyIdentifier = wykorzystuje generuje publ ic klucz do certyfikatu

Co więcej, jako wystawcę wykorzystywany jest urząd certyfikacji, a klucz prywatny ośrodka CA służy do tworzenia certyfikatu pośredniego.

To również działa i mogę zainstalować certyfikat pośredni (przy użyciu IE ponownie), jest również pokazane, że nadrzędny certyfikat jest generowany certyfikat CA i że certyfikat jest ważny.

Teraz przychodzi trudna część, w której popełniam błąd, jak sądzę. Teraz tworzę nowy certyfikat za pomocą pośredniego certyfikatu, używając następującego kodu.

KeyPair endPair = Signing.generateKeyPair("DSA", 1024, null, null); 

Map<ASN1ObjectIdentifier, Entry<Boolean, DEREncodable>> endMap = new HashMap<ASN1ObjectIdentifier, Entry<Boolean, DEREncodable>>(); 
endMap.put(X509Extensions.AuthorityKeyIdentifier, new AbstractMap.SimpleEntry<Boolean, DEREncodable>(false, new AuthorityKeyIdentifierStructure(intermediateCert))); 
endMap.put(X509Extensions.SubjectKeyIdentifier, new AbstractMap.SimpleEntry<Boolean, DEREncodable>(false, new SubjectKeyIdentifierStructure(endPair.getPublic()))); 

X509Certificate endCert = X509CertificateGenerator.generateX509Certificate(serial.add(BigInteger.valueOf(1l)), "CN=end", intermediateCert.getSubjectX500Principal().toString(), start, end, "SHA1withDSA", intermediatePair.getPrivate(), endPair.getPublic(), null, endMap); 

X509CertificateGenerator.savePemX509Certificate(endCert, endPair.getPrivate(), endWriter); 

Zasadniczo jest to to samo, co tworzenie certyfikatu pośredniego. Jednak teraz używać następujących ustawień X509Extension:

  • X509Extensions.AuthorityKeyIdentifier = ustawia certyfikat pośredni jako certyfikaty rodzica
  • X509Extensions.SubjectKeyIdentifier = używa generuje klucz publiczny dla certyfikatu

Również certyfikat pośredni jest używany jako wystawca, a jego klucz prywatny służy do tworzenia certyfikatu.

Mogę również zainstalować nowy certyfikat, ale gdy sprawdzę, czy (ponownie IE), pokazuje, że certyfikat jest jednak nieważny, ponieważ "Ten urząd certyfikacji nie jest uprawniony do wydawania certyfikatów lub certyfikat nie może być używany jako koniec -jednostka."

Więc muszę jakoś włączyć certyfikat pośredni, aby móc tworzyć nowe certyfikaty, dodając niektóre KeyUsages/ExtendedKeyUsage, które zakładam.

Czy ktoś wie, w jaki sposób włączam certyfikat pośredni, aby zrobić to, co jest mi potrzebne, lub jeśli ogólnie coś robię?

EDIT 1:

Więc dobrze zapomniałem podać kod metody który stworzył certyfikat i taki, który zapisany w formacie PEM (I przemianowano go savePemX509Certificate ponieważ stary był misguiding) .

Kod do generowania certyfikatów:

public static X509Certificate generateX509Certificate(BigInteger serialnumber, String subject, String issuer, Date start , Date end, String signAlgorithm, PrivateKey privateKey, PublicKey publicKey, String provider, Map<ASN1ObjectIdentifier, Entry<Boolean, DEREncodable>> map) throws CertificateEncodingException, InvalidKeyException, IllegalStateException, NoSuchProviderException, NoSuchAlgorithmException, SignatureException 
{ 
    if(serialnumber!=null && subject!=null && issuer!=null && start!=null && end!=null && signAlgorithm !=null && privateKey!=null && publicKey!=null) 
    { 
     //-----GENERATE THE X509 CERTIFICATE 
     X509V3CertificateGenerator certGen = new X509V3CertificateGenerator(); 
     X509Principal dnSubject = new X509Principal(subject); 
     X509Principal dnIssuer = new X509Principal(issuer); 

     certGen.setSerialNumber(serialnumber); 
     certGen.setSubjectDN(dnSubject); 
     certGen.setIssuerDN(dnIssuer); 
     certGen.setNotBefore(start); 
     certGen.setNotAfter(end); 
     certGen.setPublicKey(publicKey); 
     certGen.setSignatureAlgorithm(signAlgorithm); 

     //-----insert extension if needed 
     if(map!=null) 
      for(ASN1ObjectIdentifier extension : map.keySet()) 
       certGen.addExtension(extension, map.get(extension).getKey(), map.get(extension).getValue()); 

     return certGen.generate(privateKey, provider); 
    } 
    return null; 
} 

Kod dla saveing ​​certyfikatu i klucza:

public static boolean savePemX509Certificate(X509Certificate cert, PrivateKey key, Writer writer) throws NoSuchAlgorithmException, NoSuchProviderException, CertificateEncodingException, SignatureException, InvalidKeyException, IOException 
{  
    if(cert!=null && key!=null && writer!=null) 
    {    
     PEMWriter pemWriter = new PEMWriter(writer); 
     pemWriter.writeObject(cert); 
     pemWriter.flush(); 

     if(key!=null) 
     { 
      pemWriter.writeObject(key); 
      pemWriter.flush(); 
     } 
     pemWriter.close(); 
     return true; 
     } 
    return false; 
} 

Jak widać ja w zasadzie umieścić certyfikat i klucz w pliku, to wszystko. Wynik jest następujący i wydaje mi się dobry.

-----BEGIN CERTIFICATE----- 
MIICdjCCAjagAwIBAgIGAUDuXLRLMAkGByqGSM44BAMwDTELMAkGA1UEAwwCQ0Ew 
HhcNMTMwOTA1MTM0MzA3WhcNMTMwOTA3MTM0MzA3WjANMQswCQYDVQQDDAJDQTCC 
AbcwggEsBgcqhkjOOAQBMIIBHwKBgQD9f1OBHXUSKVLfSpwu7OTn9hG3UjzvRADD 
Hj+AtlEmaUVdQCJR+1k9jVj6v8X1ujD2y5tVbNeBO4AdNG/yZmC3a5lQpaSfn+gE 
exAiwk+7qdf+t8Yb+DtX58aophUPBPuD9tPFHsMCNVQTWhaRMvZ1864rYdcq7/Ii 
Axmd0UgBxwIVAJdgUI8VIwvMspK5gqLrhAvwWBz1AoGBAPfhoIXWmz3ey7yrXDa4 
V7l5lK+7+jrqgvlXTAs9B4JnUVlXjrrUWU/mcQcQgYC0SRZxI+hMKBYTt88JMozI 
puE8FnqLVHyNKOCjrh4rs6Z1kW6jfwv6ITVi8ftiegEkO8yk8b6oUZCJqIPf4Vrl 
nwaSi2ZegHtVJWQBTDv+z0kqA4GEAAKBgAeFoGATLbIr8+QNuxcbYJ7RhbefKWSC 
Br67Pp4Ynikxx8FZN4kCjGX7pwT1KffN3gta7jxIXNM5G3IFbs4XnYljh5TbdnjP 
9Ge3kxpwncsbMQfCqIwHh8T5gh55KaxH7yYV2mrtEEqj7NBL4thQhJe2WGwgkB9U 
NxNmLoMq3m4poyMwITAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAJ 
BgcqhkjOOAQDAy8AMCwCFFm5ybLY09y8y2uGsEnpceffy2KaAhQIyshgy3ohCLxQ 
q3CmnvC+cfT2VQ== 
-----END CERTIFICATE----- 
-----BEGIN DSA PRIVATE KEY----- 
MIIBuwIBAAKBgQD9f1OBHXUSKVLfSpwu7OTn9hG3UjzvRADDHj+AtlEmaUVdQCJR 
+1k9jVj6v8X1ujD2y5tVbNeBO4AdNG/yZmC3a5lQpaSfn+gEexAiwk+7qdf+t8Yb 
+DtX58aophUPBPuD9tPFHsMCNVQTWhaRMvZ1864rYdcq7/IiAxmd0UgBxwIVAJdg 
UI8VIwvMspK5gqLrhAvwWBz1AoGBAPfhoIXWmz3ey7yrXDa4V7l5lK+7+jrqgvlX 
TAs9B4JnUVlXjrrUWU/mcQcQgYC0SRZxI+hMKBYTt88JMozIpuE8FnqLVHyNKOCj 
rh4rs6Z1kW6jfwv6ITVi8ftiegEkO8yk8b6oUZCJqIPf4VrlnwaSi2ZegHtVJWQB 
TDv+z0kqAoGAB4WgYBMtsivz5A27FxtgntGFt58pZIIGvrs+nhieKTHHwVk3iQKM 
ZfunBPUp983eC1ruPEhc0zkbcgVuzhediWOHlNt2eM/0Z7eTGnCdyxsxB8KojAeH 
xPmCHnkprEfvJhXaau0QSqPs0Evi2FCEl7ZYbCCQH1Q3E2YugyrebikCFDJCJHtt 
NWB4LWYc4y4QvJ/l46ap 
-----END DSA PRIVATE KEY----- 

Więc po gtrig dostarczyła mi prawidłowy sposób, aby utworzyć certyfikat, skończyło się za pomocą tej metody, aby utworzyć albo normalny lub samo podpisane (jeśli klucz prywatny jest z tej samej pary kluczy jako klucza publicznego, is) certyfikat

public static X509Certificate createX509V3Certificate(X500Principal name, BigInteger serial, Date start, Date end, PublicKey pubKey, String algorithm, PrivateKey privateKey, Map<ASN1ObjectIdentifier, Entry<Boolean, ASN1Object>> map, X509Certificate parentCert) throws IOException, OperatorCreationException, CertificateException 
{ 
    if(serial!=null && start!=null && end!=null && name!=null && pubKey!=null && algorithm!=null && privateKey!=null) 
    { 
     ContentSigner signer = new JcaContentSignerBuilder(algorithm).build(privateKey); 
     X509v3CertificateBuilder certBldr = null; 
     if(parentCert==null) 
      certBldr = new JcaX509v3CertificateBuilder(name, serial, start, end, name, pubKey); 
     else 
      certBldr = new JcaX509v3CertificateBuilder(parentCert, serial, start, end, name, pubKey); 

     if(map!=null) 
      for(ASN1ObjectIdentifier extension : map.keySet()) 
       certBldr.addExtension(extension, map.get(extension).getKey(), map.get(extension).getValue()); 

     return new JcaX509CertificateConverter().setProvider("BC").getCertificate(certBldr.build(signer)); 
    } 
    return null; 
} 
+0

Co to jest „wejście” w ostatnim polu kodu? Dlaczego nie używać 'intermediateCert' zamiast' entry.getKey() '. Skąd pochodzi 'X509CertificateGenerator'? – gtrig

+0

Wpis jest pośrednim certyfikatem, właśnie zauważyłem, że nadal mam stary kod, który załadował wcześniej zapisany plik PEM i umieścił go w pozycji (w zasadzie połączenie certyfikatu i klucza). Więc wpis jest w rzeczywistości pośredniCert. – DokutoMekki

Odpowiedz

6

Coś wygląda nie tak ze sposobem, w jaki tworzysz pliki PEM. Używasz metody o nazwie, generateSelfSignedPemX509Certificate, ale naprawdę nie chcesz certyfikatu z podpisem własnym, potrzebujesz certyfikatu końcowego podpisanego przez pośredni klucz prywatny i chcesz certyfikat pośredni podpisany przez klucz prywatny CA.

Potrzebujesz również rozszerzeń basic constraints i key usage na swoich certyfikatach.

Do tworzenia certyfikatów podpisanych przez inne podmioty (bez samopodpisania), używam tych metod z Bouncy Castle, aby utworzyć certyfikat "końcowy".

ASN1Sequence seq= 
    (ASN1Sequence) new ASN1InputStream(parentPubKey.getEncoded()).readObject(); 

    SubjectPublicKeyInfo parentPubKeyInfo = new SubjectPublicKeyInfo(seq); 

    ContentSigner signer = new JcaContentSignerBuilder(algorithm).build(parentPrivKey); 

    X509v3CertificateBuilder certBldr = 
    new JcaX509v3CertificateBuilder(
     parentCert, 
     serialNum, 
     startDate, 
     endDate, 
     distName, 
     pubKey) 
    .addExtension(
      new ASN1ObjectIdentifier("2.5.29.35"), 
      false, 
      new AuthorityKeyIdentifier(parentPubKeyInfo)) 
    .addExtension(
     new ASN1ObjectIdentifier("2.5.29.19"), 
     false, 
     new BasicConstraints(false)) // true if it is allowed to sign other certs 
    .addExtension(
     new ASN1ObjectIdentifier("2.5.29.15"), 
     true, 
     new X509KeyUsage(
      X509KeyUsage.digitalSignature | 
      X509KeyUsage.nonRepudiation | 
      X509KeyUsage.keyEncipherment | 
      X509KeyUsage.dataEncipherment)); 

    // Build/sign the certificate. 
    X509CertificateHolder certHolder = certBldr.build(signer); 

    X509Certificate cert = new JcaX509CertificateConverter().setProvider(BC) 
    .getCertificate(certHolder); 

Do urzędu lub pośredniego certyfikatu, trzeba dodać SubjectKeyIdentifier rozszerzenie. Również BasicConstraints powinny być true i keyUsage powinno być:

 new X509KeyUsage(
      X509KeyUsage.keyCertSign| 
      X509KeyUsage.cRLSign)); 
+0

Przepraszamy za błędną nazwę metody, zredagowałem mój post i podałem dodatkowy kod. – DokutoMekki

+0

Więc OK, wygląda na to, że twoja odpowiedź jest rzeczywiście poprawna, potrzebowałam podstawowego rozszerzenia ograniczeń, którego brakowało w pośrednim certyfikacie. Teraz działa łańcuch certyfikatów i mogłem również użyć niedyskryfikowanego sposobu tworzenia certyfikatu. Dzięki – DokutoMekki

Powiązane problemy