/************************************************************************* * * * EJBCA: The OpenSource Certificate Authority * * * * This software is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2.1 of the License, or any later version. * * * * See terms of license at gnu.org. * * * *************************************************************************/ package org.ejbca.core.protocol; import java.io.IOException; import java.math.BigInteger; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.PrivateKey; import java.security.PublicKey; import java.security.cert.Certificate; import java.util.Date; import org.apache.log4j.Logger; import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.ASN1Set; import org.bouncycastle.asn1.ASN1Encodable; import org.bouncycastle.asn1.DERPrintableString; import org.bouncycastle.asn1.ASN1String; import org.bouncycastle.asn1.DERUTF8String; import org.bouncycastle.asn1.pkcs.Attribute; import org.bouncycastle.asn1.cms.AttributeTable; import org.bouncycastle.asn1.pkcs.CertificationRequest; import org.bouncycastle.asn1.pkcs.CertificationRequestInfo; import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.asn1.x509.Extension; import org.bouncycastle.asn1.x509.Extensions; import org.bouncycastle.asn1.x500.X500Name; import org.bouncycastle.cms.CMSSignedGenerator; import org.bouncycastle.operator.ContentVerifier; import org.bouncycastle.operator.ContentVerifierProvider; import org.bouncycastle.operator.OperatorCreationException; import org.bouncycastle.operator.jcajce.JcaContentVerifierProviderBuilder; import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequest; import org.ejbca.util.CertTools; import org.ejbca.util.RequestMessageUtils; /** * Class to handle PKCS10 request messages sent to the CA. * * @version $Id: PKCS10RequestMessage.java 7549 2009-05-22 15:15:24Z anatom $ */ public class PKCS10RequestMessage implements IRequestMessage { /** * Determines if a de-serialized file is compatible with this class. * * Maintainers must change this value if and only if the new version * of this class is not compatible with old versions. See Sun docs * for details. * */ static final long serialVersionUID = 3597275157018205137L; private static final Logger log = Logger.getLogger(PKCS10RequestMessage.class); /** Raw form of the PKCS10 message */ protected byte[] p10msg; /** manually set password */ protected String password = null; /** manually set username */ protected String username = null; /** If the CA certificate should be included in the response or not, default to true = yes */ protected boolean includeCACert = true; /** preferred digest algorithm to use in replies, if applicable */ private transient String preferredDigestAlg = CMSSignedGenerator.DIGEST_SHA1; /** The pkcs10 request message, not serialized. */ protected transient JcaPKCS10CertificationRequest pkcs10 = null; /** Type of error */ private int error = 0; /** Error text */ private String errorText = null; /** * Constructs a new empty PKCS#10 message handler object. * * @throws IOException if the request can not be parsed. */ public PKCS10RequestMessage() { // No constructor } /** * Constructs a new PKCS#10 message handler object. * * @param msg The DER encoded PKCS#10 request. * * @throws IOException if the request can not be parsed. */ public PKCS10RequestMessage(byte[] msg) throws IOException { log.trace(">PKCS10RequestMessage(byte[])"); this.p10msg = msg; init(); log.trace("PKCS10RequestMessage(ExtendedPKCS10CertificationRequest)"); p10msg = p10.getEncoded(); pkcs10 = p10; log.trace(" 0) { ret = name.substring(0, index); } else { // Perhaps there is no space, only + index = name.indexOf('+'); if (index > 0) { ret = name.substring(0, index); } } } log.debug("UserName='" + ret + "'"); return ret; } /** * Gets the issuer DN if contained in the request (the CA the request is targeted at). * * @return issuerDN of receiving CA or null. */ public String getIssuerDN() { return null; } /** * Gets the number (of CA cert) from IssuerAndSerialNumber. Combined with getIssuerDN to identify * the CA-certificate of the CA the request is targeted for. * * @return serial number of CA certificate for CA issuing CRL or null. */ public BigInteger getSerialNo() { return null; } /** * Gets the issuer DN (of CA cert) from IssuerAndSerialNumber when this is a CRL request. * * @return issuerDN of CA issuing CRL. */ public String getCRLIssuerDN() { return null; } /** * Gets the number (of CA cert) from IssuerAndSerialNumber when this is a CRL request. * * @return serial number of CA certificate for CA issuing CRL. */ public BigInteger getCRLSerialNo() { return null; } /** * Returns the string representation of the subject DN from the certification request. * * @return subject DN from certification request or null. */ public String getRequestDN() { String ret = null; X500Name name = getRequestX500Name(); if (name != null) { String dn = name.toString(); // We have to make special handling again for Cisco devices. // they will submit requests like: SN=FFFFFF+unstructuredName=Router // EJBCA does not handle this very well so we will change it to: SN=FFFFFF,unstructuredName=Router dn = dn.replace("+unstructuredName=", ",unstructuredName="); dn = dn.replace(" + unstructuredName=", ",unstructuredName="); dn = dn.replace("+unstructuredAddress=", ",unstructuredAddress="); dn = dn.replace(" + unstructuredAddress=", ",unstructuredAddress="); ret = dn; } log.debug("getRequestDN: "+ret); return ret; } /** * @see IRequestMessage#getRequestX509Name() */ public X500Name getRequestX500Name() { try { if (pkcs10 == null) { init(); } } catch (IllegalArgumentException e) { log.error("PKCS10 not initialized!"); return null; } catch (IOException e) { log.error("PKCS10 not initialized!"); return null; } // Get subject name from request return pkcs10.getSubject(); } public String getRequestAltNames() { String ret = null; try { Extensions exts = getRequestExtensions(); if (exts != null) { Extension ext = exts.getExtension(Extension.subjectAlternativeName); if (ext != null) { // Finally read the value ret = CertTools.getAltNameStringFromExtension(ext); } else { log.debug("no subject altName extension"); } } } catch (IllegalArgumentException e) { log.debug("pkcs_9_extensionRequest does not contain Extensions that it should, ignoring invalid encoded extension request."); } return ret; } /** * @see org.ejbca.core.protocol.IRequestMessage */ public Date getRequestValidityNotBefore() { return null; } /** * @see org.ejbca.core.protocol.IRequestMessage */ public Date getRequestValidityNotAfter() { return null; } /** * @see org.ejbca.core.protocol.IRequestMessage */ public Extensions getRequestExtensions() { try { if (pkcs10 == null) { init(); } } catch (IllegalArgumentException e) { log.error("PKCS10 not initialized!"); return null; } catch (IOException e) { log.error("PKCS10 not initialized!"); return null; } Extensions ret = null; // Get attributes // The X509 extension is in a a pkcs_9_at_extensionRequest AttributeTable attributes = null; CertificationRequestInfo info = CertificationRequest.getInstance(pkcs10).getCertificationRequestInfo(); if (info != null) { ASN1Set attrs = info.getAttributes(); if (attrs != null) { attributes = new AttributeTable(attrs); } } if (attributes != null) { // See if we have it embedded in an extension request instead org.bouncycastle.asn1.cms.Attribute attr = attributes.get(PKCSObjectIdentifiers.pkcs_9_at_extensionRequest); if (attr != null) { log.debug("got request extension"); ASN1Set values = attr.getAttrValues(); if (values.size() > 0) { try { ret = Extensions.getInstance(values.getObjectAt(0)); } catch (IllegalArgumentException e) { log.debug("pkcs_9_extensionRequest does not contain Extensions that it should, ignoring invalid encoded extension request."); } } } } return ret; } /** * Gets the underlying BC PKCS10CertificationRequest object. * * @return the request object */ public CertificationRequest getCertificationRequest() { try { if (pkcs10 == null) { init(); } } catch (IllegalArgumentException e) { log.error("PKCS10 not initialized!"); return null; } catch (IOException e) { log.error("PKCS10 not initialized!"); return null; } return CertificationRequest.getInstance(pkcs10); } /** * DOCUMENT ME! * * @return DOCUMENT ME! * * @throws InvalidKeyException DOCUMENT ME! * @throws NoSuchAlgorithmException DOCUMENT ME! * @throws NoSuchProviderException DOCUMENT ME! */ public boolean verify() throws InvalidKeyException, NoSuchAlgorithmException, NoSuchProviderException { return verify(null); } public boolean verify(PublicKey pubKey) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchProviderException { log.trace(">verify()"); boolean ret = false; try { if (pkcs10 == null) { init(); } JcaContentVerifierProviderBuilder verifierProviderBuilder = new JcaContentVerifierProviderBuilder(); verifierProviderBuilder.setProvider("BC"); CertificationRequest cr = CertificationRequest.getInstance(pkcs10); AlgorithmIdentifier sigAlg = cr.getSignatureAlgorithm(); if (pubKey == null) { ContentVerifierProvider verifierProvider = verifierProviderBuilder.build(pkcs10.getPublicKey()); ContentVerifier verifier = verifierProvider.get(sigAlg); ret = verifier.verify(cr.getSignature().getBytes()); } else { ContentVerifierProvider verifierProvider = verifierProviderBuilder.build(pubKey); ContentVerifier verifier = verifierProvider.get(sigAlg); ret = verifier.verify(cr.getSignature().getBytes()); } } catch (IllegalArgumentException e) { log.error("PKCS10 not inited!"); } catch (InvalidKeyException e) { log.error("Error in PKCS10-request:", e); throw e; } catch (OperatorCreationException e) { log.error("Error in PKCS10-signature:", e); } catch (IOException e) { log.error("Failed to initialize PKCS10: ", e); } log.trace("