001: package org.bouncycastle.jce.netscape;
002:
003: import java.io.ByteArrayInputStream;
004: import java.io.ByteArrayOutputStream;
005: import java.io.IOException;
006: import java.security.InvalidKeyException;
007: import java.security.KeyFactory;
008: import java.security.NoSuchAlgorithmException;
009: import java.security.NoSuchProviderException;
010: import java.security.PrivateKey;
011: import java.security.PublicKey;
012: import java.security.SecureRandom;
013: import java.security.Signature;
014: import java.security.SignatureException;
015: import java.security.spec.InvalidKeySpecException;
016: import java.security.spec.X509EncodedKeySpec;
017:
018: import org.bouncycastle.asn1.ASN1Encodable;
019: import org.bouncycastle.asn1.ASN1EncodableVector;
020: import org.bouncycastle.asn1.ASN1InputStream;
021: import org.bouncycastle.asn1.ASN1Sequence;
022: import org.bouncycastle.asn1.DERBitString;
023: import org.bouncycastle.asn1.DERIA5String;
024: import org.bouncycastle.asn1.DERObject;
025: import org.bouncycastle.asn1.DEROutputStream;
026: import org.bouncycastle.asn1.DERSequence;
027: import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
028: import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
029:
030: /**
031: *
032: *
033: * Handles NetScape certificate request (KEYGEN), these are constructed as:
034: * <pre><code>
035: * SignedPublicKeyAndChallenge ::= SEQUENCE {
036: * publicKeyAndChallenge PublicKeyAndChallenge,
037: * signatureAlgorithm AlgorithmIdentifier,
038: * signature BIT STRING
039: * }
040: * </pre>
041: *
042: * PublicKey's encoded-format has to be X.509.
043: *
044: **/
045: public class NetscapeCertRequest extends ASN1Encodable {
046: AlgorithmIdentifier sigAlg;
047: AlgorithmIdentifier keyAlg;
048: byte sigBits[];
049: String challenge;
050: DERBitString content;
051: PublicKey pubkey;
052:
053: private static ASN1Sequence getReq(byte[] r) throws IOException {
054: ASN1InputStream aIn = new ASN1InputStream(
055: new ByteArrayInputStream(r));
056:
057: return ASN1Sequence.getInstance(aIn.readObject());
058: }
059:
060: public NetscapeCertRequest(byte[] req) throws IOException {
061: this (getReq(req));
062: }
063:
064: public NetscapeCertRequest(ASN1Sequence spkac) {
065: try {
066:
067: //
068: // SignedPublicKeyAndChallenge ::= SEQUENCE {
069: // publicKeyAndChallenge PublicKeyAndChallenge,
070: // signatureAlgorithm AlgorithmIdentifier,
071: // signature BIT STRING
072: // }
073: //
074: if (spkac.size() != 3) {
075: throw new IllegalArgumentException(
076: "invalid SPKAC (size):" + spkac.size());
077: }
078:
079: sigAlg = new AlgorithmIdentifier((ASN1Sequence) spkac
080: .getObjectAt(1));
081: sigBits = ((DERBitString) spkac.getObjectAt(2)).getBytes();
082:
083: //
084: // PublicKeyAndChallenge ::= SEQUENCE {
085: // spki SubjectPublicKeyInfo,
086: // challenge IA5STRING
087: // }
088: //
089: ASN1Sequence pkac = (ASN1Sequence) spkac.getObjectAt(0);
090:
091: if (pkac.size() != 2) {
092: throw new IllegalArgumentException(
093: "invalid PKAC (len): " + pkac.size());
094: }
095:
096: challenge = ((DERIA5String) pkac.getObjectAt(1))
097: .getString();
098:
099: //this could be dangerous, as ASN.1 decoding/encoding
100: //could potentially alter the bytes
101: content = new DERBitString(pkac);
102:
103: SubjectPublicKeyInfo pubkeyinfo = new SubjectPublicKeyInfo(
104: (ASN1Sequence) pkac.getObjectAt(0));
105:
106: X509EncodedKeySpec xspec = new X509EncodedKeySpec(
107: new DERBitString(pubkeyinfo).getBytes());
108:
109: keyAlg = pubkeyinfo.getAlgorithmId();
110: pubkey = KeyFactory.getInstance(
111: keyAlg.getObjectId().getId(), "BC").generatePublic(
112: xspec);
113:
114: } catch (Exception e) {
115: throw new IllegalArgumentException(e.toString());
116: }
117: }
118:
119: public NetscapeCertRequest(String challenge,
120: AlgorithmIdentifier signing_alg, PublicKey pub_key)
121: throws NoSuchAlgorithmException, InvalidKeySpecException,
122: NoSuchProviderException {
123:
124: this .challenge = challenge;
125: sigAlg = signing_alg;
126: pubkey = pub_key;
127:
128: ASN1EncodableVector content_der = new ASN1EncodableVector();
129: content_der.add(getKeySpec());
130: //content_der.add(new SubjectPublicKeyInfo(sigAlg, new RSAPublicKeyStructure(pubkey.getModulus(), pubkey.getPublicExponent()).getDERObject()));
131: content_der.add(new DERIA5String(challenge));
132:
133: content = new DERBitString(new DERSequence(content_der));
134: }
135:
136: public String getChallenge() {
137: return challenge;
138: }
139:
140: public void setChallenge(String value) {
141: challenge = value;
142: }
143:
144: public AlgorithmIdentifier getSigningAlgorithm() {
145: return sigAlg;
146: }
147:
148: public void setSigningAlgorithm(AlgorithmIdentifier value) {
149: sigAlg = value;
150: }
151:
152: public AlgorithmIdentifier getKeyAlgorithm() {
153: return keyAlg;
154: }
155:
156: public void setKeyAlgorithm(AlgorithmIdentifier value) {
157: keyAlg = value;
158: }
159:
160: public PublicKey getPublicKey() {
161: return pubkey;
162: }
163:
164: public void setPublicKey(PublicKey value) {
165: pubkey = value;
166: }
167:
168: public boolean verify(String challenge)
169: throws NoSuchAlgorithmException, InvalidKeyException,
170: SignatureException, NoSuchProviderException {
171: if (!challenge.equals(this .challenge)) {
172: return false;
173: }
174:
175: //
176: // Verify the signature .. shows the response was generated
177: // by someone who knew the associated private key
178: //
179: Signature sig = Signature.getInstance(sigAlg.getObjectId()
180: .getId(), "BC");
181: sig.initVerify(pubkey);
182: sig.update(content.getBytes());
183:
184: return sig.verify(sigBits);
185: }
186:
187: public void sign(PrivateKey priv_key)
188: throws NoSuchAlgorithmException, InvalidKeyException,
189: SignatureException, NoSuchProviderException,
190: InvalidKeySpecException {
191: sign(priv_key, null);
192: }
193:
194: public void sign(PrivateKey priv_key, SecureRandom rand)
195: throws NoSuchAlgorithmException, InvalidKeyException,
196: SignatureException, NoSuchProviderException,
197: InvalidKeySpecException {
198: Signature sig = Signature.getInstance(sigAlg.getObjectId()
199: .getId(), "BC");
200:
201: if (rand != null) {
202: sig.initSign(priv_key, rand);
203: } else {
204: sig.initSign(priv_key);
205: }
206:
207: ByteArrayOutputStream baos = new ByteArrayOutputStream();
208: DEROutputStream deros = new DEROutputStream(baos);
209:
210: ASN1EncodableVector pkac = new ASN1EncodableVector();
211:
212: pkac.add(getKeySpec());
213: pkac.add(new DERIA5String(challenge));
214:
215: try {
216: deros.writeObject(new DERSequence(pkac));
217: deros.close();
218: } catch (IOException ioe) {
219: throw new SignatureException(ioe.getMessage());
220: }
221:
222: sig.update(baos.toByteArray());
223:
224: sigBits = sig.sign();
225: }
226:
227: private DERObject getKeySpec() throws NoSuchAlgorithmException,
228: InvalidKeySpecException, NoSuchProviderException {
229: ByteArrayOutputStream baos = new ByteArrayOutputStream();
230:
231: DERObject obj = null;
232: try {
233:
234: baos.write(pubkey.getEncoded());
235: baos.close();
236:
237: ASN1InputStream derin = new ASN1InputStream(
238: new ByteArrayInputStream(baos.toByteArray()));
239:
240: obj = derin.readObject();
241: } catch (IOException ioe) {
242: throw new InvalidKeySpecException(ioe.getMessage());
243: }
244: return obj;
245: }
246:
247: public DERObject toASN1Object() {
248: ASN1EncodableVector spkac = new ASN1EncodableVector();
249: ASN1EncodableVector pkac = new ASN1EncodableVector();
250:
251: try {
252: pkac.add(getKeySpec());
253: } catch (Exception e) {
254: //ignore
255: }
256:
257: pkac.add(new DERIA5String(challenge));
258:
259: spkac.add(new DERSequence(pkac));
260: spkac.add(sigAlg);
261: spkac.add(new DERBitString(sigBits));
262:
263: return new DERSequence(spkac);
264: }
265: }
|