KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > ejbca > core > protocol > cmp > CrmfRequestMessage


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.cmp;
15
16 import java.io.ByteArrayInputStream JavaDoc;
17 import java.io.ByteArrayOutputStream JavaDoc;
18 import java.io.IOException JavaDoc;
19 import java.math.BigInteger JavaDoc;
20 import java.security.InvalidKeyException JavaDoc;
21 import java.security.KeyFactory JavaDoc;
22 import java.security.NoSuchAlgorithmException JavaDoc;
23 import java.security.NoSuchProviderException JavaDoc;
24 import java.security.PrivateKey JavaDoc;
25 import java.security.PublicKey JavaDoc;
26 import java.security.Signature JavaDoc;
27 import java.security.SignatureException JavaDoc;
28 import java.security.cert.Certificate JavaDoc;
29 import java.security.cert.X509Certificate JavaDoc;
30 import java.security.spec.X509EncodedKeySpec JavaDoc;
31 import java.util.Date JavaDoc;
32
33 import org.apache.commons.lang.StringUtils;
34 import org.apache.log4j.Logger;
35 import org.bouncycastle.asn1.ASN1InputStream;
36 import org.bouncycastle.asn1.ASN1OctetString;
37 import org.bouncycastle.asn1.DERBitString;
38 import org.bouncycastle.asn1.DEREncodable;
39 import org.bouncycastle.asn1.DERObject;
40 import org.bouncycastle.asn1.DEROctetString;
41 import org.bouncycastle.asn1.DEROutputStream;
42 import org.bouncycastle.asn1.DERUTF8String;
43 import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
44 import org.bouncycastle.asn1.x509.GeneralName;
45 import org.bouncycastle.asn1.x509.GeneralNames;
46 import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
47 import org.bouncycastle.asn1.x509.Time;
48 import org.bouncycastle.asn1.x509.X509Extension;
49 import org.bouncycastle.asn1.x509.X509Extensions;
50 import org.bouncycastle.asn1.x509.X509Name;
51 import org.bouncycastle.cms.CMSSignedGenerator;
52 import org.ejbca.core.protocol.IRequestMessage;
53 import org.ejbca.core.protocol.IResponseMessage;
54 import org.ejbca.core.protocol.RequestMessageUtils;
55 import org.ejbca.util.Base64;
56 import org.ejbca.util.CertTools;
57
58 import com.novosec.pkix.asn1.cmp.PKIBody;
59 import com.novosec.pkix.asn1.cmp.PKIHeader;
60 import com.novosec.pkix.asn1.cmp.PKIMessage;
61 import com.novosec.pkix.asn1.crmf.AttributeTypeAndValue;
62 import com.novosec.pkix.asn1.crmf.CRMFObjectIdentifiers;
63 import com.novosec.pkix.asn1.crmf.CertReqMessages;
64 import com.novosec.pkix.asn1.crmf.CertReqMsg;
65 import com.novosec.pkix.asn1.crmf.CertRequest;
66 import com.novosec.pkix.asn1.crmf.CertTemplate;
67 import com.novosec.pkix.asn1.crmf.OptionalValidity;
68 import com.novosec.pkix.asn1.crmf.POPOSigningKey;
69 import com.novosec.pkix.asn1.crmf.ProofOfPossession;
70
71 /**
72  * Certificate request message (crmf) according to RFC4211.
73  * - Supported POPO:
74  * -- raVerified (null), i.e. no POPO verification is done, it should be configurable if the CA should allow this or require a real POPO
75  * -- Self signature
76  *
77  * @author tomas
78  * @version $Id: CrmfRequestMessage.java,v 1.14.2.1 2007/03/28 12:26:55 anatom Exp $
79  */

80 public class CrmfRequestMessage extends BaseCmpMessage implements IRequestMessage {
81     
82     private static final Logger log = Logger.getLogger(CrmfRequestMessage.class);
83     
84     /**
85      * Determines if a de-serialized file is compatible with this class.
86      *
87      * Maintainers must change this value if and only if the new version
88      * of this class is not compatible with old versions. See Sun docs
89      * for <a HREF=http://java.sun.com/products/jdk/1.1/docs/guide
90      * /serialization/spec/version.doc.html> details. </a>
91      *
92      */

93     static final long serialVersionUID = 1001L;
94
95     private int requestType = 0;
96     private int requestId = 0;
97     private PKIMessage msg;
98     private CertReqMsg req;
99     private String JavaDoc b64SenderNonce = null;
100     private String JavaDoc b64TransId = null;
101     private String JavaDoc defaultCA = null;
102     private boolean allowRaVerifyPopo = false;
103     private String JavaDoc extractUsernameComponent = null;
104     /** manually set username */
105     private String JavaDoc username = null;
106     /** manually set password */
107     private String JavaDoc password = null;
108
109     /** preferred digest algorithm to use in replies, if applicable */
110     private transient String JavaDoc preferredDigestAlg = CMSSignedGenerator.DIGEST_SHA1;
111
112     /**
113      *
114      * @param header PKIHeader
115      * @param body PKIBody
116      * @param defaultCA possibility to enforce a certain CA, instead of taking the CA name from the request, if set to null the CA is taken from the request
117      * @param allowRaVerifyPopo true if we allows the user/RA to specify the POP should not be verified
118      * @param extractUsernameComponent Defines which component from the DN should be used as username in EJBCA. Can be CN, UID or nothing. Null means that the DN should have been pre-set, here it is the same as CN.
119      */

120     public CrmfRequestMessage(PKIMessage msg, String JavaDoc defaultCA, boolean allowRaVerifyPopo, String JavaDoc extractUsernameComponent) {
121         this.msg = msg;
122         PKIBody body = msg.getBody();
123         PKIHeader header = msg.getHeader();
124         requestType = body.getTagNo();
125         CertReqMessages msgs = getCertReqFromTag(body, requestType);
126         requestId = msgs.getCertReqMsg(0).getCertReq().getCertReqId().getValue().intValue();
127         this.defaultCA = defaultCA;
128         this.allowRaVerifyPopo = allowRaVerifyPopo;
129         this.extractUsernameComponent = extractUsernameComponent;
130         this.req = msgs.getCertReqMsg(0);
131         setMessage(this.msg);
132         DEROctetString os = header.getTransactionID();
133         if (os != null) {
134             byte[] val = os.getOctets();
135             if (val != null) {
136                 setTransactionId(new String JavaDoc(Base64.encode(val)));
137             }
138         }
139         os = header.getSenderNonce();
140         if (os != null) {
141             byte[] val = os.getOctets();
142             if (val != null) {
143                 setSenderNonce(new String JavaDoc(Base64.encode(val)));
144             }
145         }
146         setRecipient(header.getRecipient());
147         setSender(header.getSender());
148     }
149     
150     public PublicKey JavaDoc getRequestPublicKey() throws InvalidKeyException JavaDoc, NoSuchAlgorithmException JavaDoc, NoSuchProviderException JavaDoc {
151         CertRequest request = req.getCertReq();
152         CertTemplate templ = request.getCertTemplate();
153         SubjectPublicKeyInfo keyInfo = templ.getPublicKey();
154         PublicKey JavaDoc pk = getPublicKey(keyInfo, "BC");
155         return pk;
156     }
157     private PublicKey JavaDoc getPublicKey(SubjectPublicKeyInfo subjectPKInfo, String JavaDoc provider) throws NoSuchAlgorithmException JavaDoc, NoSuchProviderException JavaDoc, InvalidKeyException JavaDoc {
158         try {
159             X509EncodedKeySpec JavaDoc xspec = new X509EncodedKeySpec JavaDoc(new DERBitString(subjectPKInfo).getBytes());
160             AlgorithmIdentifier keyAlg = subjectPKInfo.getAlgorithmId ();
161             return KeyFactory.getInstance(keyAlg.getObjectId().getId (), provider).generatePublic(xspec);
162         } catch (java.security.spec.InvalidKeySpecException JavaDoc e) {
163             InvalidKeyException JavaDoc newe = new InvalidKeyException JavaDoc("Error decoding public key.");
164             newe.initCause(e);
165             throw newe;
166         }
167     }
168     
169     /** force a password, i.e. ignore the password in the request
170      */

171     public void setPassword(String JavaDoc pwd) {
172         this.password = pwd;
173     }
174     public String JavaDoc getPassword() {
175         String JavaDoc ret = null;
176         if (password != null) {
177             log.debug("Returning a pre-set password in CRMF request");
178             ret = password;
179         } else {
180             // If there is "Registration Token Control" containing a password, we can use that
181
AttributeTypeAndValue av = null;
182             int i = 0;
183             do {
184                 av = req.getRegInfo(i);
185                 if (av != null) {
186                     if (StringUtils.equals(CRMFObjectIdentifiers.regCtrl_regToken.getId(), av.getObjectId().getId())) {
187                         DEREncodable enc = av.getParameters();
188                         DERUTF8String str = DERUTF8String.getInstance(enc);
189                         ret = str.getString();
190                         log.debug("Found a request password in CRMF request regCtrl_regToken");
191                     }
192                 }
193                 i++;
194             } while ( (av != null) && (ret == null) );
195         }
196         if (ret == null) {
197             // Otherwise there may be Password Based HMAC/SHA-1 protection
198
// TODO
199
}
200         return ret;
201     }
202
203     /** force a username, i.e. ignore the DN/username in the request
204      */

205     public void setUsername(String JavaDoc username) {
206         this.username = username;
207     }
208     
209     public String JavaDoc getUsername() {
210         String JavaDoc ret = null;
211         if (username != null) {
212             ret = username;
213         } else {
214             // We can configure which part of the users DN should be used as username in EJBCA, for example CN or UID
215
String JavaDoc component = extractUsernameComponent;
216             if (StringUtils.isEmpty(component)) {
217                 component = "CN";
218             }
219             String JavaDoc name = CertTools.getPartFromDN(getRequestDN(), component);
220             if (name == null) {
221                 log.error("No component "+component+" in DN: "+getRequestDN());
222             } else {
223                 ret = name;
224             }
225         }
226         log.debug("Username is: "+ret);
227         return ret;
228     }
229
230     public void setIssuerDN(String JavaDoc issuer) {
231         this.defaultCA = issuer;
232     }
233     public String JavaDoc getIssuerDN() {
234         String JavaDoc ret = null;
235         CertTemplate templ = req.getCertReq().getCertTemplate();
236         X509Name name = templ.getIssuer();
237         if (name != null) {
238             ret = CertTools.stringToBCDNString(name.toString());
239         } else {
240             ret = defaultCA;
241         }
242         log.debug("Issuer DN is: "+ret);
243         return ret;
244     }
245
246     public BigInteger JavaDoc getSerialNo() {
247         return null;
248     }
249
250     public String JavaDoc getCRLIssuerDN() {
251         return null;
252     }
253
254     public BigInteger JavaDoc getCRLSerialNo() {
255         return null;
256     }
257
258     public String JavaDoc getRequestDN() {
259         String JavaDoc ret = null;
260         CertTemplate templ = req.getCertReq().getCertTemplate();
261         X509Name name = templ.getSubject();
262         if (name != null) {
263             ret = CertTools.stringToBCDNString(name.toString());
264         }
265         log.debug("Request DN is: "+ret);
266         return ret;
267     }
268     
269     public String JavaDoc getRequestAltNames() {
270         String JavaDoc ret = null;
271         CertTemplate templ = req.getCertReq().getCertTemplate();
272         X509Extensions exts = templ.getExtensions();
273         if (exts != null) {
274             X509Extension ext = exts.getExtension(X509Extensions.SubjectAlternativeName);
275             if (ext != null) {
276                 //GeneralNames
277
ASN1OctetString octs = ext.getValue();
278                 if (octs != null) {
279                     ASN1InputStream aIn = new ASN1InputStream(new ByteArrayInputStream JavaDoc(octs.getOctets()));
280                     DERObject obj;
281                     try {
282                         obj = aIn.readObject();
283                         GeneralNames gan = GeneralNames.getInstance(obj);
284                         GeneralName[] gns = gan.getNames();
285                         String JavaDoc altName = null;
286                         for (int i = 0; i < gns.length; i++) {
287                             GeneralName gn = gns[i];
288                             int tag = gn.getTagNo();
289                             DEREncodable name = gn.getName();
290                             String JavaDoc str = CertTools.getGeneralNameString(tag, name);
291                             if (altName == null) {
292                                 altName = str;
293                             } else {
294                                 altName += ", "+str;
295                             }
296                         }
297                         ret = altName;
298                     } catch (IOException JavaDoc e) {
299                         log.error("IOExceptioon parsing altNames: ", e);
300                         return null;
301                     }
302                 }
303             }
304         }
305         log.debug("Request altName is: "+ret);
306         return ret;
307     }
308
309
310     public Date JavaDoc getRequestValidityNotBefore() {
311         Date JavaDoc ret = null;
312         CertTemplate templ = req.getCertReq().getCertTemplate();
313         OptionalValidity val = templ.getValidity();
314         if (val != null) {
315             Time time = val.getNotBefore();
316             if (time != null) {
317                 ret = time.getDate();
318             }
319         }
320         log.debug("Request validity notBefore is: "+(ret == null ? "null" : ret.toString()));
321         return ret;
322     }
323     
324     public Date JavaDoc getRequestValidityNotAfter() {
325         Date JavaDoc ret = null;
326         CertTemplate templ = req.getCertReq().getCertTemplate();
327         OptionalValidity val = templ.getValidity();
328         if (val != null) {
329             Time time = val.getNotAfter();
330             if (time != null) {
331                 ret = time.getDate();
332             }
333         }
334         log.debug("Request validity notAfter is: "+(ret == null ? "null" : ret.toString()));
335         return ret;
336     }
337     
338     public boolean verify() throws InvalidKeyException JavaDoc, NoSuchAlgorithmException JavaDoc, NoSuchProviderException JavaDoc {
339         boolean ret = false;
340         ProofOfPossession pop = req.getPop();
341         if ( (pop.getRaVerified() != null) && allowRaVerifyPopo) {
342             ret = true;
343         } else if (pop.getSignature() != null) {
344             try {
345                 POPOSigningKey sk = pop.getSignature();
346                 AlgorithmIdentifier algId = sk.getAlgorithmIdentifier();
347                 log.debug("POP algorithm identifier is: "+algId.getObjectId().getId());
348                 DERBitString bs = sk.getSignature();
349                 PublicKey JavaDoc pk = getRequestPublicKey();
350                 ByteArrayOutputStream JavaDoc bao = new ByteArrayOutputStream JavaDoc();
351                 DEROutputStream out = new DEROutputStream(bao);
352                 out.writeObject(req.getCertReq());
353                 byte[] protBytes = bao.toByteArray();
354                 log.debug("POP protection bytes length: "+protBytes.length);
355                 Signature JavaDoc sig;
356                 sig = Signature.getInstance(algId.getObjectId().getId(), "BC");
357                 sig.initVerify(pk);
358                 sig.update(protBytes);
359                 ret = sig.verify(bs.getBytes());
360             } catch (IOException JavaDoc e) {
361                 log.error("Error encoding CertReqMsg: ", e);
362             } catch (SignatureException JavaDoc e) {
363                 log.error("SignatureException verifying POP: ", e);
364             }
365         }
366         return ret;
367     }
368
369     public boolean requireKeyInfo() {
370         return false;
371     }
372
373     public void setKeyInfo(X509Certificate JavaDoc cert, PrivateKey JavaDoc key, String JavaDoc provider) {
374     }
375
376     public int getErrorNo() {
377         return 0;
378     }
379
380     public String JavaDoc getErrorText() {
381         return null;
382     }
383
384     public void setSenderNonce(String JavaDoc b64nonce) {
385         this.b64SenderNonce = b64nonce;
386     }
387     public String JavaDoc getSenderNonce() {
388         return b64SenderNonce;
389     }
390
391     public void setTransactionId(String JavaDoc b64transid) {
392         this.b64TransId = b64transid;
393     }
394     public String JavaDoc getTransactionId() {
395         return b64TransId;
396     }
397
398     public byte[] getRequestKeyInfo() {
399         return null;
400     }
401
402     public String JavaDoc getPreferredDigestAlg() {
403         return preferredDigestAlg;
404     }
405
406     public boolean includeCACert() {
407         return false;
408     }
409
410     /** @see org.ejbca.core.protocol.IRequestMessage
411      */

412     public int getRequestType() {
413         return requestType;
414     }
415
416     /** @see org.ejbca.core.protocol.IRequestMessage
417      */

418     public int getRequestId() {
419         return requestId;
420     }
421
422     // Returns the subject DN from the request
423
public String JavaDoc getSubjectDN() {
424         String JavaDoc ret = null;
425         CertTemplate templ = req.getCertReq().getCertTemplate();
426         X509Name name = templ.getSubject();
427         if (name != null) {
428             ret = CertTools.stringToBCDNString(name.toString());
429         }
430         return ret;
431     }
432
433     private CertReqMessages getCertReqFromTag(PKIBody body, int tag) {
434         CertReqMessages msgs = null;
435         switch (tag) {
436         case 0:
437             msgs = body.getIr();
438             break;
439         case 2:
440             msgs = body.getCr();
441             break;
442         case 7:
443             msgs = body.getKur();
444             break;
445         case 9:
446             msgs = body.getKrr();
447             break;
448         case 13:
449             msgs = body.getCcr();
450             break;
451         default:
452             break;
453         }
454         return msgs;
455     }
456     /** @see org.ejbca.core.protocol.IRequestMessage
457      */

458     public IResponseMessage createResponseMessage(Class JavaDoc responseClass, IRequestMessage req, Certificate JavaDoc cert, PrivateKey JavaDoc signPriv, PrivateKey JavaDoc encPriv, String JavaDoc provider) {
459         return RequestMessageUtils.createResponseMessage(responseClass, req, cert, signPriv, encPriv, provider);
460     }
461 }
462
Popular Tags