diff options
Diffstat (limited to 'libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/X509ExtensionUtils.java')
-rw-r--r-- | libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/X509ExtensionUtils.java | 126 |
1 files changed, 126 insertions, 0 deletions
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/X509ExtensionUtils.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/X509ExtensionUtils.java new file mode 100644 index 000000000..54f56adb8 --- /dev/null +++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/X509ExtensionUtils.java @@ -0,0 +1,126 @@ +package org.spongycastle.cert; + +import java.io.IOException; +import java.io.OutputStream; + +import org.spongycastle.asn1.ASN1OctetString; +import org.spongycastle.asn1.x509.AuthorityKeyIdentifier; +import org.spongycastle.asn1.x509.Extension; +import org.spongycastle.asn1.x509.GeneralName; +import org.spongycastle.asn1.x509.GeneralNames; +import org.spongycastle.asn1.x509.SubjectKeyIdentifier; +import org.spongycastle.asn1.x509.SubjectPublicKeyInfo; +import org.spongycastle.operator.DigestCalculator; + +/** + * General utility class for creating calculated extensions using the standard methods. + * <p> + * <b>Note:</b> This class is not thread safe! + * </p> + */ +public class X509ExtensionUtils +{ + private DigestCalculator calculator; + + public X509ExtensionUtils(DigestCalculator calculator) + { + this.calculator = calculator; + } + + public AuthorityKeyIdentifier createAuthorityKeyIdentifier( + X509CertificateHolder certHolder) + { + if (certHolder.getVersionNumber() != 3) + { + GeneralName genName = new GeneralName(certHolder.getIssuer()); + SubjectPublicKeyInfo info = certHolder.getSubjectPublicKeyInfo(); + + return new AuthorityKeyIdentifier( + calculateIdentifier(info), new GeneralNames(genName), certHolder.getSerialNumber()); + } + else + { + GeneralName genName = new GeneralName(certHolder.getIssuer()); + Extension ext = certHolder.getExtension(Extension.subjectKeyIdentifier); + + if (ext != null) + { + ASN1OctetString str = ASN1OctetString.getInstance(ext.getParsedValue()); + + return new AuthorityKeyIdentifier( + str.getOctets(), new GeneralNames(genName), certHolder.getSerialNumber()); + } + else + { + SubjectPublicKeyInfo info = certHolder.getSubjectPublicKeyInfo(); + + return new AuthorityKeyIdentifier( + calculateIdentifier(info), new GeneralNames(genName), certHolder.getSerialNumber()); + } + } + } + + public AuthorityKeyIdentifier createAuthorityKeyIdentifier(SubjectPublicKeyInfo publicKeyInfo) + { + return new AuthorityKeyIdentifier(calculateIdentifier(publicKeyInfo)); + } + + /** + * Return a RFC 3280 type 1 key identifier. As in: + * <pre> + * (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). + * </pre> + * @param publicKeyInfo the key info object containing the subjectPublicKey field. + * @return the key identifier. + */ + public SubjectKeyIdentifier createSubjectKeyIdentifier( + SubjectPublicKeyInfo publicKeyInfo) + { + return new SubjectKeyIdentifier(calculateIdentifier(publicKeyInfo)); + } + + /** + * Return a RFC 3280 type 2 key identifier. As in: + * <pre> + * (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. + * </pre> + * @param publicKeyInfo the key info object containing the subjectPublicKey field. + * @return the key identifier. + */ + public SubjectKeyIdentifier createTruncatedSubjectKeyIdentifier(SubjectPublicKeyInfo publicKeyInfo) + { + byte[] digest = calculateIdentifier(publicKeyInfo); + byte[] id = new byte[8]; + + System.arraycopy(digest, digest.length - 8, id, 0, id.length); + + id[0] &= 0x0f; + id[0] |= 0x40; + + return new SubjectKeyIdentifier(id); + } + + private byte[] calculateIdentifier(SubjectPublicKeyInfo publicKeyInfo) + { + byte[] bytes = publicKeyInfo.getPublicKeyData().getBytes(); + + OutputStream cOut = calculator.getOutputStream(); + + try + { + cOut.write(bytes); + + cOut.close(); + } + catch (IOException e) + { // it's hard to imagine this happening, but yes it does! + throw new CertRuntimeException("unable to calculate identifier: " + e.getMessage(), e); + } + + return calculator.getDigest(); + } +} |