1 | |
|
2 | |
|
3 | |
|
4 | |
|
5 | |
|
6 | |
|
7 | |
|
8 | |
|
9 | |
|
10 | |
|
11 | |
|
12 | |
|
13 | |
|
14 | |
|
15 | |
|
16 | |
package eu.emi.security.authn.x509.helpers.proxy; |
17 | |
|
18 | |
import java.io.ByteArrayInputStream; |
19 | |
import java.io.IOException; |
20 | |
import java.math.BigInteger; |
21 | |
import java.security.InvalidKeyException; |
22 | |
import java.security.NoSuchAlgorithmException; |
23 | |
import java.security.NoSuchProviderException; |
24 | |
import java.security.PrivateKey; |
25 | |
import java.security.SecureRandom; |
26 | |
import java.security.Signature; |
27 | |
import java.security.SignatureException; |
28 | |
import java.security.cert.CertificateException; |
29 | |
import java.security.cert.CertificateFactory; |
30 | |
import java.security.cert.CertificateParsingException; |
31 | |
import java.security.cert.X509Certificate; |
32 | |
import java.util.Date; |
33 | |
|
34 | |
import org.bouncycastle.asn1.ASN1Encoding; |
35 | |
import org.bouncycastle.asn1.ASN1Object; |
36 | |
import org.bouncycastle.asn1.ASN1EncodableVector; |
37 | |
import org.bouncycastle.asn1.ASN1Primitive; |
38 | |
import org.bouncycastle.asn1.ASN1ObjectIdentifier; |
39 | |
import org.bouncycastle.asn1.DERBitString; |
40 | |
import org.bouncycastle.asn1.ASN1Integer; |
41 | |
import org.bouncycastle.asn1.DERSequence; |
42 | |
import org.bouncycastle.asn1.x500.X500Name; |
43 | |
import org.bouncycastle.asn1.x509.AlgorithmIdentifier; |
44 | |
import org.bouncycastle.asn1.x509.ExtensionsGenerator; |
45 | |
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; |
46 | |
import org.bouncycastle.asn1.x509.TBSCertificate; |
47 | |
import org.bouncycastle.asn1.x509.Time; |
48 | |
import org.bouncycastle.asn1.x509.V3TBSCertificateGenerator; |
49 | |
|
50 | |
|
51 | |
|
52 | |
|
53 | |
|
54 | |
|
55 | |
|
56 | |
public class X509v3CertificateBuilder |
57 | |
{ |
58 | |
private V3TBSCertificateGenerator tbsGen; |
59 | |
private ExtensionsGenerator extGenerator; |
60 | |
|
61 | |
|
62 | |
|
63 | |
|
64 | |
|
65 | |
|
66 | |
|
67 | |
|
68 | |
|
69 | |
|
70 | |
|
71 | |
|
72 | |
public X509v3CertificateBuilder(X500Name issuer, BigInteger serial, |
73 | |
Date notBefore, Date notAfter, X500Name subject, |
74 | |
SubjectPublicKeyInfo publicKeyInfo) |
75 | 26 | { |
76 | 26 | tbsGen = new V3TBSCertificateGenerator(); |
77 | 26 | tbsGen.setSubject(subject); |
78 | 26 | tbsGen.setSerialNumber(new ASN1Integer(serial)); |
79 | 26 | tbsGen.setIssuer(issuer); |
80 | 26 | tbsGen.setStartDate(new Time(notBefore)); |
81 | 26 | tbsGen.setEndDate(new Time(notAfter)); |
82 | 26 | tbsGen.setSubject(subject); |
83 | 26 | tbsGen.setSubjectPublicKeyInfo(publicKeyInfo); |
84 | 26 | extGenerator = new ExtensionsGenerator(); |
85 | 26 | } |
86 | |
|
87 | |
|
88 | |
|
89 | |
|
90 | |
|
91 | |
|
92 | |
|
93 | |
|
94 | |
|
95 | |
|
96 | |
public X509v3CertificateBuilder addExtension(ASN1ObjectIdentifier oid, |
97 | |
boolean isCritical, ASN1Object value) throws IOException |
98 | |
{ |
99 | 54 | extGenerator.addExtension(oid, isCritical, value); |
100 | 54 | return this; |
101 | |
} |
102 | |
|
103 | |
|
104 | |
|
105 | |
|
106 | |
|
107 | |
|
108 | |
|
109 | |
|
110 | |
|
111 | |
|
112 | |
|
113 | |
|
114 | |
|
115 | |
|
116 | |
|
117 | |
|
118 | |
|
119 | |
public X509Certificate build(PrivateKey key, AlgorithmIdentifier sigAlg, |
120 | |
String sigAlgName, String provider, SecureRandom random) |
121 | |
throws InvalidKeyException, CertificateParsingException, |
122 | |
NoSuchProviderException, NoSuchAlgorithmException, |
123 | |
SignatureException, IOException |
124 | |
{ |
125 | 26 | if (sigAlg == null || sigAlgName == null) |
126 | 0 | throw new IllegalStateException( |
127 | |
"no signature algorithm specified"); |
128 | 26 | if (key == null) |
129 | 0 | throw new IllegalStateException( |
130 | |
"no private key specified"); |
131 | 26 | tbsGen.setSignature(sigAlg); |
132 | |
|
133 | 26 | if (!extGenerator.isEmpty()) |
134 | 26 | tbsGen.setExtensions(extGenerator.generate()); |
135 | |
|
136 | 26 | TBSCertificate toSign = tbsGen.generateTBSCertificate(); |
137 | 26 | return sign(toSign, sigAlg, sigAlgName, key, provider, random); |
138 | |
} |
139 | |
|
140 | |
private X509Certificate sign(TBSCertificate toSign, AlgorithmIdentifier sigAlg, |
141 | |
String sigAlgName, |
142 | |
PrivateKey key, String provider, SecureRandom random) |
143 | |
throws InvalidKeyException, NoSuchProviderException, NoSuchAlgorithmException, |
144 | |
SignatureException, IOException, CertificateParsingException |
145 | |
|
146 | |
{ |
147 | 26 | byte[] signature = calculateSignature(sigAlgName, |
148 | |
provider, key, random, toSign); |
149 | |
|
150 | 26 | ASN1EncodableVector v = new ASN1EncodableVector(); |
151 | 26 | v.add(toSign); |
152 | 26 | v.add(sigAlg.toASN1Primitive()); |
153 | 26 | v.add(new DERBitString(signature)); |
154 | 26 | DERSequence derCertificate = new DERSequence(v); |
155 | |
CertificateFactory factory; |
156 | |
try |
157 | |
{ |
158 | 26 | factory = CertificateFactory.getInstance("X.509"); |
159 | 26 | ByteArrayInputStream bais = new ByteArrayInputStream(derCertificate.getEncoded(ASN1Encoding.DER)); |
160 | 26 | return (X509Certificate) factory.generateCertificate(bais); |
161 | 0 | } catch (CertificateException e) |
162 | |
{ |
163 | 0 | throw new RuntimeException("The generated proxy " + |
164 | |
"certificate was not parsed by the JDK", e); |
165 | |
} |
166 | |
} |
167 | |
|
168 | |
private byte[] calculateSignature(String sigName, String provider, PrivateKey key, |
169 | |
SecureRandom random, ASN1Object object) |
170 | |
throws IOException, NoSuchProviderException, |
171 | |
NoSuchAlgorithmException, InvalidKeyException, |
172 | |
SignatureException |
173 | |
{ |
174 | |
Signature sig; |
175 | |
|
176 | 26 | if (provider != null) |
177 | 0 | sig = Signature.getInstance(sigName, provider); |
178 | |
else |
179 | 26 | sig = Signature.getInstance(sigName); |
180 | |
|
181 | 26 | if (random != null) |
182 | 0 | sig.initSign(key, random); |
183 | |
else |
184 | 26 | sig.initSign(key); |
185 | |
|
186 | 26 | sig.update(object.getEncoded(ASN1Encoding.DER)); |
187 | 26 | return sig.sign(); |
188 | |
} |
189 | |
|
190 | |
|
191 | |
|
192 | |
|
193 | |
|
194 | |
|
195 | |
|
196 | |
public static AlgorithmIdentifier extractAlgorithmId(X509Certificate cert) |
197 | |
throws IOException |
198 | |
{ |
199 | 26 | String oid = cert.getSigAlgOID(); |
200 | 26 | byte params[] = cert.getSigAlgParams(); |
201 | 26 | if (params != null) |
202 | |
{ |
203 | 7 | ASN1Primitive derParams = ASN1Primitive.fromByteArray(params); |
204 | 7 | return new AlgorithmIdentifier(new ASN1ObjectIdentifier(oid), |
205 | |
derParams); |
206 | |
} else |
207 | |
{ |
208 | 19 | return new AlgorithmIdentifier(new ASN1ObjectIdentifier(oid)); |
209 | |
} |
210 | |
} |
211 | |
} |