KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > ejbca > core > protocol > ScepResponseMessage


1 /*************************************************************************
2  * *
3  * EJBCA: The OpenSource Certificate Authority *
4  * *
5  * This software is free software; you can redistribute it and/or *
6  * modify it under the terms of the GNU Lesser General Public *
7  * License as published by the Free Software Foundation; either *
8  * version 2.1 of the License, or any later version. *
9  * *
10  * See terms of license at gnu.org. *
11  * *
12  *************************************************************************/

13
14 package org.ejbca.core.protocol;
15
16 import java.io.IOException JavaDoc;
17 import java.security.InvalidAlgorithmParameterException JavaDoc;
18 import java.security.InvalidKeyException JavaDoc;
19 import java.security.NoSuchAlgorithmException JavaDoc;
20 import java.security.NoSuchProviderException JavaDoc;
21 import java.security.PrivateKey JavaDoc;
22 import java.security.cert.CRL JavaDoc;
23 import java.security.cert.CertStore JavaDoc;
24 import java.security.cert.CertStoreException JavaDoc;
25 import java.security.cert.Certificate JavaDoc;
26 import java.security.cert.CertificateEncodingException JavaDoc;
27 import java.security.cert.CertificateException JavaDoc;
28 import java.security.cert.CollectionCertStoreParameters JavaDoc;
29 import java.security.cert.X509Certificate JavaDoc;
30 import java.util.ArrayList JavaDoc;
31 import java.util.Hashtable JavaDoc;
32
33 import javax.ejb.ObjectNotFoundException JavaDoc;
34
35 import org.apache.log4j.Logger;
36 import org.bouncycastle.asn1.DERObjectIdentifier;
37 import org.bouncycastle.asn1.DEROctetString;
38 import org.bouncycastle.asn1.DERPrintableString;
39 import org.bouncycastle.asn1.DERSet;
40 import org.bouncycastle.asn1.cms.Attribute;
41 import org.bouncycastle.asn1.cms.AttributeTable;
42 import org.bouncycastle.asn1.smime.SMIMECapability;
43 import org.bouncycastle.cms.CMSEnvelopedData;
44 import org.bouncycastle.cms.CMSEnvelopedDataGenerator;
45 import org.bouncycastle.cms.CMSException;
46 import org.bouncycastle.cms.CMSProcessable;
47 import org.bouncycastle.cms.CMSProcessableByteArray;
48 import org.bouncycastle.cms.CMSSignedData;
49 import org.bouncycastle.cms.CMSSignedDataGenerator;
50 import org.bouncycastle.cms.CMSSignedGenerator;
51 import org.ejbca.core.model.ca.SignRequestException;
52 import org.ejbca.core.model.ra.NotFoundException;
53 import org.ejbca.util.Base64;
54 import org.ejbca.util.CertTools;
55
56 /**
57  * A response message for scep (pkcs7).
58  *
59  * @version $Id: ScepResponseMessage.java,v 1.7 2006/10/22 09:05:05 anatom Exp $
60  */

61 public class ScepResponseMessage implements IResponseMessage {
62     /**
63      * Determines if a de-serialized file is compatible with this class.
64      *
65      * Maintainers must change this value if and only if the new version
66      * of this class is not compatible with old versions. See Sun docs
67      * for <a HREF=http://java.sun.com/products/jdk/1.1/docs/guide
68      * /serialization/spec/version.doc.html> details. </a>
69      *
70      */

71     static final long serialVersionUID = 2016710353393853878L;
72
73     private static Logger log = Logger.getLogger(ScepResponseMessage.class);
74
75     /** The encoded response message */
76     private byte[] responseMessage = null;
77
78     /** status for the response */
79     private ResponseStatus status = ResponseStatus.SUCCESS;
80
81     /** Possible fail information in the response. Defaults to 'badRequest (2)'. */
82     private FailInfo failInfo = FailInfo.BAD_REQUEST;
83
84     /** Possible clear text error information in the response. Defaults to null. */
85     private String JavaDoc failText = null;
86
87     /**
88      * SenderNonce. This is base64 encoded bytes
89      */

90     private String JavaDoc senderNonce = null;
91     /**
92      * RecipientNonce in a response is the senderNonce from the request. This is base64 encoded bytes
93      */

94     private String JavaDoc recipientNonce = null;
95
96     /** transaction id */
97     private String JavaDoc transactionId = null;
98
99     /** recipient key identifier, usually IssuerAndSerialno in X509 world. */
100     private byte[] recipientKeyInfo = null;
101
102     /** The un-encoded response message itself */
103     private transient CMSSignedData signedData = null;
104
105     /** Certificate to be in response message, not serialized */
106     private transient Certificate JavaDoc cert = null;
107     private transient CRL JavaDoc crl = null;
108     /** Certificate for the signer of the response message (CA) */
109     private transient X509Certificate JavaDoc signCert = null;
110     /** Private key used to sign the response message */
111     private transient PrivateKey JavaDoc signKey = null;
112     /** The default provider is BC, if nothing else is specified when setting SignKeyInfo */
113     private transient String JavaDoc provider = "BC";
114     /** If the CA certificate should be included in the reponse or not, default to true = yes */
115     private transient boolean includeCACert = true;
116
117     /** Default digest algorithm for SCEP response message, can be overridden */
118     private transient String JavaDoc digestAlg = CMSSignedGenerator.DIGEST_MD5;
119     /**
120      * Sets the complete certificate in the response message.
121      *
122      * @param cert certificate in the response message.
123      */

124     public void setCertificate(Certificate JavaDoc cert) {
125         this.cert = cert;
126     }
127
128     /**
129      * Sets the CRL (if present) in the response message.
130      *
131      * @param crl crl in the response message.
132      */

133     public void setCrl(CRL JavaDoc crl) {
134         this.crl = crl;
135     }
136
137     /** @see org.ejbca.core.protocol.IResponseMessage#setIncludeCACert
138      *
139      */

140     public void setIncludeCACert(boolean incCACert) {
141         this.includeCACert = incCACert;
142     }
143
144     /**
145      * Gets the response message in the default encoding format.
146      *
147      * @return the response message in the default encoding format.
148      */

149     public byte[] getResponseMessage() throws IOException JavaDoc, CertificateEncodingException JavaDoc {
150         return responseMessage;
151     }
152
153     /**
154      * Sets the status of the response message.
155      *
156      * @param status status of the response.
157      */

158     public void setStatus(ResponseStatus status) {
159         this.status = status;
160     }
161
162     /**
163      * Gets the status of the response message.
164      *
165      * @return status status of the response.
166      */

167     public ResponseStatus getStatus() {
168         return status;
169     }
170
171     /**
172      * Sets info about reason for failure.
173      *
174      * @param failInfo reason for failure.
175      */

176     public void setFailInfo(FailInfo failInfo) {
177         this.failInfo = failInfo;
178     }
179
180     /**
181      * Gets info about reason for failure.
182      *
183      * @return failInfo reason for failure.
184      */

185     public FailInfo getFailInfo() {
186         return failInfo;
187     }
188
189     public void setFailText(String JavaDoc failText) {
190         this.failText = failText;
191     }
192
193     public String JavaDoc getFailText() {
194         return this.failText;
195     }
196
197     /**
198      * Create encrypts and creates signatures as needed to produce a complete response message. If
199      * needed setSignKeyInfo and setEncKeyInfo must be called before this method. After this is
200      * called the response message can be retrieved with getResponseMessage();
201      *
202      * @return True if signature/encryption was successful, false if it failed, request should not
203      * be sent back i failed.
204      *
205      * @throws IOException If input/output or encoding failed.
206      * @throws InvalidKeyException If the key used for signing/encryption is invalid.
207      * @throws NoSuchProviderException if there is an error with the Provider.
208      * @throws NoSuchAlgorithmException if the signature on the request is done with an unhandled
209      * algorithm.
210      * @throws ObjectNotFoundException
211      *
212      * @see #setSignKeyInfo
213      * @see #setEncKeyInfo
214      */

215     public boolean create()
216             throws IOException JavaDoc, InvalidKeyException JavaDoc, NoSuchAlgorithmException JavaDoc, NoSuchProviderException JavaDoc, SignRequestException, NotFoundException JavaDoc {
217         boolean ret = false;
218
219         try {
220
221             if (status.equals(ResponseStatus.SUCCESS)) {
222                 log.debug("Creating a STATUS_OK message.");
223             } else {
224                 if (status.equals(ResponseStatus.FAILURE)) {
225                     log.debug("Creating a STATUS_FAILED message (or throwing an exception).");
226                     if (failInfo.equals(FailInfo.WRONG_AUTHORITY)) {
227                         throw new SignRequestException(failText);
228                     }
229                     if (failInfo.equals(FailInfo.INCORRECT_DATA)) {
230                         throw new NotFoundException JavaDoc(failText);
231                     }
232
233                 } else {
234                     log.debug("Creating a STATUS_PENDING message.");
235                 }
236             }
237
238             CMSProcessable msg;
239             // The signed data to be enveloped
240
CMSSignedData s = null;
241             // Create encrypted response if this is success and NOT a CRL response message
242
if (status.equals(ResponseStatus.SUCCESS)) {
243
244                 CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
245                 // Add the issued certificate to the signed portion of the CMS (as signer, degenerate case)
246
ArrayList JavaDoc certList = new ArrayList JavaDoc();
247                 if (crl != null) {
248                     log.debug("Adding CRL to response message (inner signer)");
249                     certList.add(crl);
250                 } else if (cert != null) {
251                     log.debug("Adding certificates to response message");
252                     certList.add(cert);
253                     // Add the CA cert, it's optional but Cisco VPN client complains if it isn't there
254
if (includeCACert) {
255                         certList.add(signCert);
256                     }
257                 }
258                 CertStore JavaDoc certs = CertStore.getInstance("Collection",
259                         new CollectionCertStoreParameters JavaDoc(certList), "BC");
260
261                 // Create the signed CMS message to be contained inside the envelope
262
// this message does not contain any message, and no signerInfo
263
CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
264                 gen.addCertificatesAndCRLs(certs);
265                 s = gen.generate(null, false, "BC");
266
267                 // Envelope the CMS message
268
if (recipientKeyInfo != null) {
269                     try {
270                         X509Certificate JavaDoc rec = CertTools.getCertfromByteArray(recipientKeyInfo);
271                         log.debug("Added recipient information - issuer: '" + CertTools.getIssuerDN(rec) + "', serno: '" + rec.getSerialNumber().toString(16));
272                         edGen.addKeyTransRecipient(rec);
273                     } catch (CertificateException JavaDoc e) {
274                         throw new IOException JavaDoc("Can not decode recipients self signed certificate!");
275                     }
276                 } else {
277                     edGen.addKeyTransRecipient((X509Certificate JavaDoc) cert);
278                 }
279                 CMSEnvelopedData ed = edGen.generate(new CMSProcessableByteArray(s.getEncoded()),
280                         SMIMECapability.dES_CBC.getId(), "BC");
281
282                 log.debug("Enveloped data is " + ed.getEncoded().length + " bytes long");
283                 msg = new CMSProcessableByteArray(ed.getEncoded());
284             } else {
285                 // Create an empty message here
286
msg = new CMSProcessableByteArray("PrimeKey".getBytes());
287             }
288
289             // Create the outermost signed data
290
CMSSignedDataGenerator gen1 = new CMSSignedDataGenerator();
291
292             // add authenticated attributes...status, transactionId, sender- and recipientNonce and more...
293
Hashtable JavaDoc attributes = new Hashtable JavaDoc();
294             DERObjectIdentifier oid;
295             Attribute attr;
296             DERSet value;
297             
298             // Content Type
299
/* Added automagically by CMSSignedDataGenerator
300             oid = PKCSObjectIdentifiers.pkcs_9_at_contentType;
301             value = new DERSet(PKCSObjectIdentifiers.data);
302             attr = new Attribute(oid, value);
303             attributes.put(attr.getAttrType(), attr);
304             */

305
306             // Message digest
307
/* Added automagically by CMSSignedDataGenerator
308             byte[] digest = null;
309             if (s != null) {
310                 MessageDigest md = MessageDigest.getInstance("SHA1");
311                 digest = md.digest(s.getEncoded());
312             } else {
313                 digest = new byte[]{0};
314             }
315             oid = PKCSObjectIdentifiers.pkcs_9_at_messageDigest;
316             value = new DERSet(new DEROctetString(digest));
317             attr = new Attribute(oid, value);
318             attributes.put(attr.getAttrType(), attr);
319             */

320
321             // Message type (certrep)
322
oid = new DERObjectIdentifier(ScepRequestMessage.id_messageType);
323             value = new DERSet(new DERPrintableString("3"));
324             attr = new Attribute(oid, value);
325             attributes.put(attr.getAttrType(), attr);
326
327             // TransactionId
328
if (transactionId != null) {
329                 oid = new DERObjectIdentifier(ScepRequestMessage.id_transId);
330                 log.debug("Added transactionId: " + transactionId);
331                 value = new DERSet(new DERPrintableString(transactionId));
332                 attr = new Attribute(oid, value);
333                 attributes.put(attr.getAttrType(), attr);
334             }
335
336             // status
337
oid = new DERObjectIdentifier(ScepRequestMessage.id_pkiStatus);
338             value = new DERSet(new DERPrintableString(status.getValue()));
339             attr = new Attribute(oid, value);
340             attributes.put(attr.getAttrType(), attr);
341
342             if (status.equals(ResponseStatus.FAILURE)) {
343                 oid = new DERObjectIdentifier(ScepRequestMessage.id_failInfo);
344                 log.debug("Added failInfo: " + failInfo.getValue());
345                 value = new DERSet(new DERPrintableString(failInfo.getValue()));
346                 attr = new Attribute(oid, value);
347                 attributes.put(attr.getAttrType(), attr);
348             }
349
350             // senderNonce
351
if (senderNonce != null) {
352                 oid = new DERObjectIdentifier(ScepRequestMessage.id_senderNonce);
353                 log.debug("Added senderNonce: " + senderNonce);
354                 value = new DERSet(new DEROctetString(Base64.decode(senderNonce.getBytes())));
355                 attr = new Attribute(oid, value);
356                 attributes.put(attr.getAttrType(), attr);
357             }
358
359             // recipientNonce
360
if (recipientNonce != null) {
361                 oid = new DERObjectIdentifier(ScepRequestMessage.id_recipientNonce);
362                 log.debug("Added recipientNonce: " + recipientNonce);
363                 value = new DERSet(new DEROctetString(Base64.decode(recipientNonce.getBytes())));
364                 attr = new Attribute(oid, value);
365                 attributes.put(attr.getAttrType(), attr);
366             }
367
368             // Add our signer info and sign the message
369
gen1.addSigner(signKey, signCert, digestAlg,
370                     new AttributeTable(attributes), null);
371             signedData = gen1.generate(msg, true, provider);
372             responseMessage = signedData.getEncoded();
373             if (responseMessage != null) {
374                 ret = true;
375             }
376         } catch (InvalidAlgorithmParameterException JavaDoc e) {
377             log.error("Error creating CertStore: ", e);
378         } catch (CertStoreException JavaDoc e) {
379             log.error("Error creating CertStore: ", e);
380         } catch (CMSException e) {
381             log.error("Error creating CMS message: ", e);
382         }
383
384         return ret;
385     }
386
387     /**
388      * indicates if this message needs recipients public and private key to sign. If this returns
389      * true, setSignKeyInfo() should be called.
390      *
391      * @return True if public and private key is needed.
392      */

393     public boolean requireSignKeyInfo() {
394         return true;
395     }
396
397     /**
398      * indicates if this message needs recipients public and private key to encrypt. If this
399      * returns true, setEncKeyInfo() should be called.
400      *
401      * @return True if public and private key is needed.
402      */

403     public boolean requireEncKeyInfo() {
404         return false;
405     }
406
407     /**
408      * Sets the public and private key needed to sign the message. Must be set if
409      * requireSignKeyInfo() returns true.
410      *
411      * @param cert certificate containing the public key.
412      * @param key private key.
413      * @param provider the provider to use, if the private key is on a HSM you must use a special provider. If null is given, the default BC provider is used.
414      *
415      * @see #requireSignKeyInfo()
416      */

417     public void setSignKeyInfo(X509Certificate JavaDoc cert, PrivateKey JavaDoc key, String JavaDoc prov) {
418         this.signCert = cert;
419         this.signKey = key;
420         if (prov != null) {
421             this.provider = prov;
422         }
423     }
424
425     /**
426      * Sets the public and private key needed to encrypt the message. Must be set if
427      * requireEncKeyInfo() returns true.
428      *
429      * @param cert certificate containing the public key.
430      * @param key private key.
431      * @param provider the provider to use, if the private key is on a HSM you must use a special provider. If null is given, the default BC provider is used.
432      *
433      * @see #requireEncKeyInfo()
434      */

435     public void setEncKeyInfo(X509Certificate JavaDoc cert, PrivateKey JavaDoc key, String JavaDoc provider) {
436         // We don't need these.
437
}
438
439     /**
440      * Sets a senderNonce if it should be present in the response
441      *
442      * @param senderNonce a string of base64 encoded bytes
443      */

444     public void setSenderNonce(String JavaDoc senderNonce) {
445         this.senderNonce = senderNonce;
446     }
447
448     /**
449      * Sets a recipient if it should be present in the response
450      *
451      * @param recipientNonce a string of base64 encoded bytes
452      */

453     public void setRecipientNonce(String JavaDoc recipientNonce) {
454         this.recipientNonce = recipientNonce;
455     }
456
457     /**
458      * Sets a transaction identifier if it should be present in the response
459      *
460      * @param transactionId transaction id
461      */

462     public void setTransactionId(String JavaDoc transactionId) {
463         this.transactionId = transactionId;
464     }
465
466     /**
467      * Sets recipient key info, key id or similar. This is the requestors self-signed cert from the request message.
468      *
469      * @param recipientKeyInfo key info
470      */

471     public void setRecipientKeyInfo(byte[] recipientKeyInfo) {
472         this.recipientKeyInfo = recipientKeyInfo;
473     }
474
475     /** @see org.ejca.core.protocol.IResponseMessage
476      */

477     public void setPreferredDigestAlg(String JavaDoc digest) {
478         this.digestAlg = digest;
479     }
480
481     /** @see org.ejca.core.protocol.IResponseMessage
482      */

483     public void setRequestType(int reqtype) {
484     }
485
486     /** @see org.ejca.core.protocol.IResponseMessage
487      */

488     public void setRequestId(int reqid) {
489     }
490
491     /** @see org.ejca.core.protocol.IResponseMessage
492      */

493     public void setProtectionParamsFromRequest(IRequestMessage reqMsg) {
494     }
495 }
496
Popular Tags