Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to prove that one certificate is issuer of another certificates

I have two certificate. One certificate is issuer of another certificate.

how can I see with java code that, my issuer certificate is really issuer?

I know that AuthorityKeyIdentifier of my certificate and SubjectKeyIdentifie of issuer certifiactes must be the same. I checked and they are the same.

but with java code I have that result:

    CertificateFactory certFactory = CertificateFactory.getInstance("X.509");

    InputStream usrCertificateIn = new FileInputStream("/usr.cer");
    X509Certificate cert = (X509Certificate) certFactory.generateCertificate(usrCertificateIn);

    InputStream SiningCACertificateIn = new FileInputStream("/siningCA.cer");
    X509Certificate issuer = (X509Certificate) certFactory.generateCertificate(SiningCACertificateIn);

    byte[] octets = (ASN1OctetString.getInstance(cert.getExtensionValue("2.5.29.35")).getOctets());     
    System.out.println(Arrays.toString(octets) + " bouncycastle, AuthorityKeyIdentifier");
    System.out.println(Arrays.toString(cert.getExtensionValue("2.5.29.35")) + "java.security, AuthorityKeyIdentifier");

    octets = ASN1OctetString.getInstance(issuer.getExtensionValue("2.5.29.14")).getOctets();
    System.out.println((Arrays.toString(octets) + "bouncycastle, SubjectKeyIdentifie "));
    System.out.println(Arrays.toString(issuer.getExtensionValue("2.5.29.14")) + "java.security, SubjectKeyIdentifie ");

adn the result is that:

[48, 22, -128, 20, 52, -105, 49, -70, -24, 78, 127, -113, -25, 55, 39, 99, 46, 6, 31, 66, -55, -86, -79, 113] bouncycastle, AuthorityKeyIdentifier

[4, 24, 48, 22, -128, 20, 52, -105, 49, -70, -24, 78, 127, -113, -25, 55, 39, 99, 46, 6, 31, 66, -55, -86, -79, 113]java.security, AuthorityKeyIdentifier

and another byte array that MUST BE THE SAME, BUT IT IS NOT another bytes is added at the beginning of the array.

[4, 20, 52, -105, 49, -70, -24, 78, 127, -113, -25, 55, 39, 99, 46, 6, 31, 66, -55, -86, -79, 113]bouncycastle, SubjectKeyIdentifie

[4, 22, 4, 20, 52, -105, 49, -70, -24, 78, 127, -113, -25, 55, 39, 99, 46, 6, 31, 66, -55, -86, -79, 113]java.security, SubjectKeyIdentifie

question 1) Can I calculates the key Identifiers to get the same Arrays?

question 2) is there another way in order to prove that one certificate is issuer of another certificates.

like image 598
grep Avatar asked Jul 26 '13 09:07

grep


2 Answers

AuthorityKeyIdentifier and SubjectKeyIdentifier are defined differently:

AuthorityKeyIdentifier ::= SEQUENCE {
  keyIdentifier             [0] KeyIdentifier           OPTIONAL,
  authorityCertIssuer       [1] GeneralNames            OPTIONAL,
  authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL  }

SubjectKeyIdentifier ::= KeyIdentifier

KeyIdentifier ::= OCTET STRING

(sections 4.2.1.1 and 4.2.1.2 of RFC 5280)

Thus, merely comparing the extension values cannot work, instead you have to extract the KeyIdentifier contents and compare them, e.g. using BouncyCastle ASN.1 helper classes.

BTW, the actual key identifier bytes are only

52, -105, 49, -70, -24, 78, 127, -113, -25, 55, 39, 99, 46, 6, 31, 66, -55, -86, -79, 113

The 4, 20 before that indicates an OCTET STRING, 20 bytes long. In the AuthorityKeyIdentifier the 4 is replaced by the tag [0] (byte -128) due to implicit tagging.

The 48, 22 before that in your AuthorityKeyIdentifier means (constructed) SEQUENCE, 22 bytes long.

Etc. etc.

Thus,

Can I calculates the key Identifiers to get the same Arrays?

Yes, drill down to the actual KeyIdentifier OCTET STRING values.

is there another way in order to prove that one certificate is issuer of another certificates

Well, you can check whether the signature in the certificate is signed by the private key associated with the assumed issuer certificate by verifying against that certificate's public key.

PS: Concerning the question in the comments

is key identifier's length always 20? is it fixed? may be no, is not it?

No, it is not. The before mentioned RFC 5280 says:

For CA certificates, subject key identifiers SHOULD be derived from
the public key or a method that generates unique values.  Two common
methods for generating key identifiers from the public key are:

  (1) The keyIdentifier is composed of the 160-bit SHA-1 hash of the
       value of the BIT STRING subjectPublicKey (excluding the tag,
       length, and number of unused bits).
  (2) The keyIdentifier is composed of a four-bit type field with
       the value 0100 followed by the least significant 60 bits of
       the SHA-1 hash of the value of the BIT STRING
       subjectPublicKey (excluding the tag, length, and number of
       unused bits).

Other methods of generating unique numbers are also acceptable.

I assume your CA uses method 1 (160 bit = 20 bytes) but this is merely a common method, not even something explicitly recommended, let alone required. Thus, no, you cannot count on the identifier being 20 bytes long.

PPS: Concerning the question in the comments

Isn't the signature the only way to truly prove one cert is issued by another?

That is no prove of the issuer-issuedBy relation either, it merely proves (at least to a certain degree) that the private key associated with the assumed issuer certificate signed the inspected certificate but there are situations where the same private-public key pair is used in multiple certificates.

In essence you need to do multiple complementary test and even then have to trust the CA not to do weird stuff. Not long ago e.g. the Swisscom changed one of their CA certificates to include an additional extension or critical attribute (I'd have to look up the details; I think someone certifying them demanded that change), and by the certificate signature verification test old signer certificates now seem to be issued by the new CA certificate even though the owners of the signer certificates might not be aware of that new extension/critical attribute.

So eventually real life simply is not as simple as one would like it to be...

like image 161
mkl Avatar answered Oct 08 '22 11:10

mkl


To prove one certificate was issued by another, you should prove it was signed by the private key corresponding to the public key in the issuing certificate.

Let's call 2 certificates caCert and issuedCert. These are of type X509Certificate.

The Java code to prove issuedCert is signed by the entity represented by caCert is quite simple.

PublicKey caPubKey = caCert.getPublicKey();

issuedCert.verify(caPubKey);

If the verify method returns without throwing an exception, then issuedCert was signed by the private key corresponding to the public key in caCert.

like image 33
gtrig Avatar answered Oct 08 '22 12:10

gtrig