Skip to content

Instantly share code, notes, and snippets.

@harbulot
Created August 2, 2010 00:15
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save harbulot/503932 to your computer and use it in GitHub Desktop.
Save harbulot/503932 to your computer and use it in GitHub Desktop.
<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>
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());
}
}
}
@harbulot
Copy link
Author

harbulot commented Aug 2, 2010

Output:

Certificate Request ID: 4053541819
CertTemplate sequence: [[0]2, [5]CN=Fred, [6]org.bouncycastle.asn1.x509.SubjectPublicKeyInfo@ab891d8c, [9]org.bouncycastle.asn1.x509.X509Extensions@7d9bf1fa]
Serial number: null
Algorithm identifier: null
Issuer: null
Optional validity: null
Subject: CN=Fred
Pub key exponent:65537
Pub key modulus:20482361067505909550158319948853634525949010535781089454718399751009506789428571021587125579633063638189969945686250801775384164634598547305949292819507980448942188692355995112794234310530718629141468779301534783079156896038810280748327158818470285628540921338361620851414355983511745511905773972932660194685430217117064065729656746614805943722927491090279146265005585361991928028939030650537570605479492364576681207869473971190752393983689851451243894821790233841313813923339567823152206520999522117449003654390104602288291311320146848168002577881381925069941088934044924040605251845045958535866465867283717792449361
X.509 extension with OID=2.5.29.15: #030205e0
POP type: 1
POP object: org.bouncycastle.asn1.crmf.POPOSigningKey@c4d12531
signatureAlgorithmIdentifier: 1.2.840.113549.1.1.5
Signature verified? true
attrTypeAndValue: 1.3.6.1.5.5.7.5.1.1
attrTypeAndValue: 1.3.6.1.5.5.7.5.1.2

@harbulot
Copy link
Author

harbulot commented Aug 2, 2010

I should have referenced this RFC instead: http://tools.ietf.org/html/rfc4211

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment