Created
August 2, 2010 00:15
-
-
Save harbulot/503932 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<dependencies> | |
<dependency> | |
<groupId>org.bouncycastle</groupId> | |
<artifactId>bcprov-jdk16</artifactId> | |
<version>1.45</version> | |
</dependency> | |
<dependency> | |
<groupId>commons-codec</groupId> | |
<artifactId>commons-codec</artifactId> | |
<version>1.4</version> | |
</dependency> | |
</dependencies> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.Enumeration; | |
import org.apache.commons.codec.binary.Base64; | |
import org.bouncycastle.asn1.ASN1InputStream; | |
import org.bouncycastle.asn1.ASN1Sequence; | |
import org.bouncycastle.asn1.DERBitString; | |
import org.bouncycastle.asn1.DEREncodable; | |
import org.bouncycastle.asn1.DERInteger; | |
import org.bouncycastle.asn1.DERObjectIdentifier; | |
import org.bouncycastle.asn1.DERTaggedObject; | |
import org.bouncycastle.asn1.crmf.AttributeTypeAndValue; | |
import org.bouncycastle.asn1.crmf.CertReqMessages; | |
import org.bouncycastle.asn1.crmf.CertReqMsg; | |
import org.bouncycastle.asn1.crmf.CertRequest; | |
import org.bouncycastle.asn1.crmf.CertTemplate; | |
import org.bouncycastle.asn1.crmf.OptionalValidity; | |
import org.bouncycastle.asn1.crmf.POPOSigningKey; | |
import org.bouncycastle.asn1.x509.AlgorithmIdentifier; | |
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; | |
import org.bouncycastle.asn1.x509.X509Extension; | |
import org.bouncycastle.asn1.x509.X509Extensions; | |
import org.bouncycastle.asn1.x509.X509Name; | |
import org.bouncycastle.crypto.digests.SHA1Digest; | |
import org.bouncycastle.crypto.params.AsymmetricKeyParameter; | |
import org.bouncycastle.crypto.params.RSAKeyParameters; | |
import org.bouncycastle.crypto.signers.RSADigestSigner; | |
import org.bouncycastle.crypto.util.PublicKeyFactory; | |
/* | |
* http://tools.ietf.org/html/rfc2511 | |
*/ | |
public class TestCrmf { | |
public static final String crmfExampleBase64 = "" | |
+ "MIICrjCCAqowggGOAgUA8ZwjuzCCAU6AAQKlETAPMQ0wCwYDVQQDEwRGcmVkpoIB" | |
+ "IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAokBlzCgMUeyiiLy9hONX3V2H" | |
+ "QICRZZ7bOhgSokwbuflj8BInIl7oSAWXrjFJd0Hz9+13vPg+uOlhUkfThpcPFiVe" | |
+ "+W8UfU7t0bXZOmP42O/oZRs3nnjiDHN2V++txsOs+Qjc8EQJcpgJ03npPz7SK5ph" | |
+ "bIN6LtLDVflrLOWeN4XCXJ4rRUPfKU38q5nWWCW1ULXv7Q+d00XA9rpWQPg2bZln" | |
+ "uB4Xf3/PiwFOZiYI9D+qVGhiVONZeGMp/KQNp8t5WRZJgvUvgpuXApP+5HJsI4Pt" | |
+ "+3/T97aJvtoV5YeubIIzio7w4YikiDrkA/E6c5rCSOiAFmSpvEEF6+WHS2PDUQID" | |
+ "AQABqRAwDgYDVR0PAQH/BAQDAgXgMDMwFQYJKwYBBQUHBQEBDAhyZWdUb2tlbjAa" | |
+ "BgkrBgEFBQcFAQIMDWF1dGhlbnRpY2F0b3KhggEUMA0GCSqGSIb3DQEBBQUAA4IB" | |
+ "AQA3BR/SAhR2t8PRD0FslXE6td2cjMzU7UVp+L9PdZCUxwQAcbVYTYLWCNZbsgAU" | |
+ "IwDGBdqGn/9dfkU+1nwoxRAZ+Ti2ZgfmpagFXTV1bBEoNGs0fp1TkO7ey/ZBCNbw" | |
+ "uLeD4cgKNtNy2johpvb+s2ybuxmFn5vETmrlpGe8K37EqJ8DtMaQaf5pay7RElES" | |
+ "VBcr2UqHD+cf0ehvmTrtlnmx7HJh0JO5RGypufvpQCZhzt2/lgQq6lq3EuprcLXD" | |
+ "iKqAEmCNU+5NHDhozb4Di2rixMaPz6QzxdlPUysZxMiCRSXD5z+yut9SA+TML7Bj" | |
+ "ohyEdV8jcA4trDEh6zXa9ciy"; | |
/* ASN.1 structure of this example. | |
0 686: SEQUENCE { | |
4 682: SEQUENCE { | |
8 398: SEQUENCE { | |
12 5: INTEGER 00 F1 9C 23 BB | |
19 334: SEQUENCE { | |
23 1: [0] 02 | |
26 17: [5] { | |
28 15: SEQUENCE { | |
30 13: SET { | |
32 11: SEQUENCE { | |
34 3: OBJECT IDENTIFIER commonName (2 5 4 3) | |
39 4: PrintableString 'Fred' | |
: } | |
: } | |
: } | |
: } | |
45 290: [6] { | |
49 13: SEQUENCE { | |
51 9: OBJECT IDENTIFIER rsaEncryption (1 2 840 113549 1 1 1) | |
62 0: NULL | |
: } | |
64 271: BIT STRING | |
: 30 82 01 0A 02 82 01 01 00 A2 40 65 CC 28 0C 51 | |
: EC A2 88 BC BD 84 E3 57 DD 5D 87 40 80 91 65 9E | |
: DB 3A 18 12 A2 4C 1B B9 F9 63 F0 12 27 22 5E E8 | |
: 48 05 97 AE 31 49 77 41 F3 F7 ED 77 BC F8 3E B8 | |
: E9 61 52 47 D3 86 97 0F 16 25 5E F9 6F 14 7D 4E | |
: ED D1 B5 D9 3A 63 F8 D8 EF E8 65 1B 37 9E 78 E2 | |
: 0C 73 76 57 EF AD C6 C3 AC F9 08 DC F0 44 09 72 | |
: 98 09 D3 79 E9 3F 3E D2 2B 9A 61 6C 83 7A 2E D2 | |
: C3 55 F9 6B 2C E5 9E 37 85 C2 5C 9E 2B 45 43 DF | |
: 29 4D FC AB 99 D6 58 25 B5 50 B5 EF ED 0F 9D D3 | |
: 45 C0 F6 BA 56 40 F8 36 6D 99 67 B8 1E 17 7F 7F | |
: CF 8B 01 4E 66 26 08 F4 3F AA 54 68 62 54 E3 59 | |
: 78 63 29 FC A4 0D A7 CB 79 59 16 49 82 F5 2F 82 | |
: 9B 97 02 93 FE E4 72 6C 23 83 ED FB 7F D3 F7 B6 | |
: 89 BE DA 15 E5 87 AE 6C 82 33 8A 8E F0 E1 88 A4 | |
: 88 3A E4 03 F1 3A 73 9A C2 48 E8 80 16 64 A9 BC | |
: 41 05 EB E5 87 4B 63 C3 51 02 03 01 00 01 | |
: } | |
339 16: [9] { | |
341 14: SEQUENCE { | |
343 3: OBJECT IDENTIFIER keyUsage (2 5 29 15) | |
348 1: BOOLEAN TRUE | |
351 4: OCTET STRING 03 02 05 E0 | |
: } | |
: } | |
: } | |
357 51: SEQUENCE { | |
359 21: SEQUENCE { | |
361 9: OBJECT IDENTIFIER regToken (1 3 6 1 5 5 7 5 1 1) | |
372 8: UTF8String 'regToken' | |
: } | |
382 26: SEQUENCE { | |
384 9: OBJECT IDENTIFIER authenticator (1 3 6 1 5 5 7 5 1 2) | |
395 13: UTF8String 'authenticator' | |
: } | |
: } | |
: } | |
410 276: [1] { | |
414 13: SEQUENCE { | |
416 9: OBJECT IDENTIFIER | |
: sha1withRSAEncryption (1 2 840 113549 1 1 5) | |
427 0: NULL | |
: } | |
429 257: BIT STRING | |
: 37 05 1F D2 02 14 76 B7 C3 D1 0F 41 6C 95 71 3A | |
: B5 DD 9C 8C CC D4 ED 45 69 F8 BF 4F 75 90 94 C7 | |
: 04 00 71 B5 58 4D 82 D6 08 D6 5B B2 00 14 23 00 | |
: C6 05 DA 86 9F FF 5D 7E 45 3E D6 7C 28 C5 10 19 | |
: F9 38 B6 66 07 E6 A5 A8 05 5D 35 75 6C 11 28 34 | |
: 6B 34 7E 9D 53 90 EE DE CB F6 41 08 D6 F0 B8 B7 | |
: 83 E1 C8 0A 36 D3 72 DA 3A 21 A6 F6 FE B3 6C 9B | |
: BB 19 85 9F 9B C4 4E 6A E5 A4 67 BC 2B 7E C4 A8 | |
: 9F 03 B4 C6 90 69 FE 69 6B 2E D1 12 51 12 54 17 | |
: 2B D9 4A 87 0F E7 1F D1 E8 6F 99 3A ED 96 79 B1 | |
: EC 72 61 D0 93 B9 44 6C A9 B9 FB E9 40 26 61 CE | |
: DD BF 96 04 2A EA 5A B7 12 EA 6B 70 B5 C3 88 AA | |
: 80 12 60 8D 53 EE 4D 1C 38 68 CD BE 03 8B 6A E2 | |
: C4 C6 8F CF A4 33 C5 D9 4F 53 2B 19 C4 C8 82 45 | |
: 25 C3 E7 3F B2 BA DF 52 03 E4 CC 2F B0 63 A2 1C | |
: 84 75 5F 23 70 0E 2D AC 31 21 EB 35 DA F5 C8 B2 | |
: } | |
: } | |
: } | |
*/ | |
public static void main(String[] args) throws Exception { | |
ASN1InputStream asn1InputStream = new ASN1InputStream(Base64 | |
.decodeBase64(crmfExampleBase64)); | |
CertReqMessages certReqMessages = CertReqMessages | |
.getInstance(asn1InputStream.readObject()); | |
CertReqMsg certReqMsg = certReqMessages.toCertReqMsgArray()[0]; | |
CertRequest certRequest = certReqMsg.getCertReq(); | |
/* (see RFC 2511) | |
CertRequest ::= SEQUENCE { | |
certReqId INTEGER, -- ID for matching request and reply | |
certTemplate CertTemplate, -- Selected fields of cert to be issued | |
controls Controls OPTIONAL } -- Attributes affecting issuance | |
*/ | |
System.out.println("Certificate Request ID: " | |
+ certRequest.getCertReqId()); | |
CertTemplate certTemplate = certRequest.getCertTemplate(); | |
/* (see RFC 2511) | |
CertTemplate ::= SEQUENCE { | |
version [0] Version OPTIONAL, | |
serialNumber [1] INTEGER OPTIONAL, | |
signingAlg [2] AlgorithmIdentifier OPTIONAL, | |
issuer [3] Name OPTIONAL, | |
validity [4] OptionalValidity OPTIONAL, | |
subject [5] Name OPTIONAL, | |
publicKey [6] SubjectPublicKeyInfo OPTIONAL, | |
issuerUID [7] UniqueIdentifier OPTIONAL, | |
subjectUID [8] UniqueIdentifier OPTIONAL, | |
extensions [9] Extensions OPTIONAL } | |
*/ | |
DERInteger serialNumber = null; | |
AlgorithmIdentifier algorithmIdentifier = null; | |
X509Name issuer = null; | |
OptionalValidity optionalValidity = null; | |
X509Name subject = null; | |
SubjectPublicKeyInfo subjectPublicKeyInfo = null; | |
X509Extensions extensions = null; | |
ASN1Sequence certTemplateSeq = (ASN1Sequence) certTemplate | |
.getDERObject(); | |
System.out.println("CertTemplate sequence: " + certTemplateSeq); | |
@SuppressWarnings("unchecked") | |
Enumeration<DEREncodable> certTemplateSeqEnum = certTemplateSeq | |
.getObjects(); | |
while (certTemplateSeqEnum.hasMoreElements()) { | |
DEREncodable seqItem = certTemplateSeqEnum.nextElement(); | |
DERTaggedObject taggedObj = (DERTaggedObject) seqItem; | |
DEREncodable value = taggedObj.getObjectParser( | |
taggedObj.getTagNo(), true); | |
if (taggedObj.getTagNo() == 1) { | |
serialNumber = (DERInteger) value; | |
} else if (taggedObj.getTagNo() == 2) { | |
algorithmIdentifier = AlgorithmIdentifier.getInstance( | |
taggedObj, false); | |
} else if (taggedObj.getTagNo() == 3) { | |
issuer = X509Name.getInstance(taggedObj, true); | |
} else if (taggedObj.getTagNo() == 4) { | |
optionalValidity = OptionalValidity.getInstance(value | |
.getDERObject()); | |
} else if (taggedObj.getTagNo() == 5) { | |
subject = X509Name.getInstance(taggedObj, true); | |
} else if (taggedObj.getTagNo() == 6) { | |
subjectPublicKeyInfo = SubjectPublicKeyInfo.getInstance( | |
taggedObj, false); | |
} else if (taggedObj.getTagNo() == 9) { | |
extensions = X509Extensions.getInstance(taggedObj, false); | |
} | |
} | |
System.out.println("Serial number: " + serialNumber); | |
System.out.println("Algorithm identifier: " + algorithmIdentifier); | |
System.out.println("Issuer: " + issuer); | |
System.out.println("Optional validity: " + optionalValidity); | |
System.out.println("Subject: " + subject); | |
AsymmetricKeyParameter keyParam = PublicKeyFactory | |
.createKey(subjectPublicKeyInfo); | |
// TODO: handle other types of keys. | |
if (keyParam instanceof RSAKeyParameters) { | |
RSAKeyParameters rsaKeyParam = (RSAKeyParameters) keyParam; | |
System.out.println("Pub key exponent:" + rsaKeyParam.getExponent()); | |
System.out.println("Pub key modulus:" + rsaKeyParam.getModulus()); | |
} | |
@SuppressWarnings("unchecked") | |
Enumeration<DERObjectIdentifier> extensionsOids = extensions.oids(); | |
while (extensionsOids.hasMoreElements()) { | |
DERObjectIdentifier oid = extensionsOids.nextElement(); | |
X509Extension extension = extensions.getExtension(oid); | |
System.out.println(String.format("X.509 extension with OID=%s: %s", | |
oid, extension.getValue())); | |
} | |
System.out.println("POP type: " + certReqMsg.getPop().getType()); | |
System.out.println("POP object: " + certReqMsg.getPop().getObject()); | |
POPOSigningKey popoSigningKey = (POPOSigningKey) certReqMsg.getPop() | |
.getObject(); | |
ASN1Sequence seq = (ASN1Sequence) popoSigningKey.toASN1Object(); | |
AlgorithmIdentifier signatureAlgorithmIdentifier = null; | |
DERBitString signature = null; | |
@SuppressWarnings("unchecked") | |
Enumeration<DEREncodable> seqEnum = seq.getObjects(); | |
while (seqEnum.hasMoreElements()) { | |
DEREncodable seqItem = seqEnum.nextElement(); | |
if (signatureAlgorithmIdentifier == null) { | |
if (seqItem instanceof AlgorithmIdentifier) { | |
signatureAlgorithmIdentifier = (AlgorithmIdentifier) seqItem; | |
} | |
} else { | |
signature = (DERBitString) seqItem; | |
} | |
} | |
System.out.println("signatureAlgorithmIdentifier: " | |
+ signatureAlgorithmIdentifier.getObjectId()); | |
// TODO: check that the signatureAlgorithmIdentifier is indeed SHA-1 and RSA key | |
// 1.2.840.113549.1.1.5 (otherwise, use other appropriate algorithm). | |
SHA1Digest digest = new SHA1Digest(); | |
RSADigestSigner signer = new RSADigestSigner(digest); | |
signer.init(false, keyParam); | |
signer.update(certRequest.getDEREncoded(), 0, certRequest | |
.getDEREncoded().length); | |
System.out.println("Signature verified? " | |
+ signer.verifySignature(signature.getBytes())); | |
for (AttributeTypeAndValue attrTypeAndValue : certReqMsg.getCertReq() | |
.getControls().toAttributeTypeAndValueArray()) { | |
System.out.println("attrTypeAndValue: " | |
+ attrTypeAndValue.getType()); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Output: