diff options
Diffstat (limited to 'pki/base/util/src/netscape/security/pkcs/PKCS10.java')
-rw-r--r-- | pki/base/util/src/netscape/security/pkcs/PKCS10.java | 350 |
1 files changed, 350 insertions, 0 deletions
diff --git a/pki/base/util/src/netscape/security/pkcs/PKCS10.java b/pki/base/util/src/netscape/security/pkcs/PKCS10.java new file mode 100644 index 000000000..832741faf --- /dev/null +++ b/pki/base/util/src/netscape/security/pkcs/PKCS10.java @@ -0,0 +1,350 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package netscape.security.pkcs; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.io.IOException; +import java.security.cert.CertificateException; +import java.security.NoSuchAlgorithmException; +import java.security.InvalidKeyException; +import java.security.Signature; +import java.security.SignatureException; +import java.security.PublicKey; + + +import netscape.security.util.*; // DER +import netscape.security.x509.AlgorithmId; +import netscape.security.x509.X509Key; +import netscape.security.x509.X500Name; +import netscape.security.x509.X500Signer; +import netscape.security.x509.X500Signer; + +/** + * PKCS #10 certificate requests are created and sent to Certificate + * Authorities, which then create X.509 certificates and return them to + * the entity which created the certificate request. These cert requests + * basically consist of the subject's X.500 name and public key, signed + * using the corresponding private key. + * + * The ASN.1 syntax for a Certification Request is: + * <pre> + * CertificationRequest ::= SEQUENCE { + * certificationRequestInfo CertificationRequestInfo, + * signatureAlgorithm SignatureAlgorithmIdentifier, + * signature Signature + * } + * + * SignatureAlgorithmIdentifier ::= AlgorithmIdentifier + * Signature ::= BIT STRING + * + * CertificationRequestInfo ::= SEQUENCE { + * version Version, + * subject Name, + * subjectPublicKeyInfo SubjectPublicKeyInfo, + * attributes [0] IMPLICIT Attributes + * } + * Attributes ::= SET OF Attribute + * </pre> + * + * @author David Brownell + * @author Amit Kapoor + * @author Hemma Prafullchandra + * @version 1.28 + */ +public class PKCS10 +{ + /** + * Constructs an unsigned PKCS #10 certificate request. Before this + * request may be used, it must be encoded and signed. Then it + * must be retrieved in some conventional format (e.g. string). + * + * @param publicKey the public key that should be placed + * into the certificate generated by the CA. + */ + public PKCS10 (X509Key publicKey) + { + subjectPublicKeyInfo = publicKey; + attributeSet = new PKCS10Attributes(); + } + + + /** + * Constructs an unsigned PKCS #10 certificate request. Before this + * request may be used, it must be encoded and signed. Then it + * must be retrieved in some conventional format (e.g. string). + * + * @param publicKey the public key that should be placed + * into the certificate generated by the CA. + * @param attributes additonal set of PKCS10 attributes requested + * for in the certificate. + */ + public PKCS10 (X509Key publicKey, PKCS10Attributes attributes) + { + subjectPublicKeyInfo = publicKey; + if (attributes != null) + attributeSet = attributes; + else + attributeSet = new PKCS10Attributes(); + } + + + /** + * Parses an encoded, signed PKCS #10 certificate request, verifying + * the request's signature as it does so. This constructor would + * typically be used by a Certificate Authority, from which a new + * certificate would then be constructed. + * + * @param data the DER-encoded PKCS #10 request. + * @param sigver boolean specifies signature verification enabled or not + * @exception IOException for low level errors reading the data + * @exception SignatureException when the signature is invalid + * @exception NoSuchAlgorithmException when the signature + * algorithm is not supported in this environment + */ + public PKCS10 (byte data [], boolean sigver) + throws IOException, SignatureException, NoSuchAlgorithmException,java.security.NoSuchProviderException + { + DerInputStream in; + DerValue seq []; + AlgorithmId id; + byte sigData []; + Signature sig; + + certificateRequest = data; + + // + // Outer sequence: request, signature algorithm, signature. + // Parse, and prepare to verify later. + // + in = new DerInputStream (data); + seq = in.getSequence (3); + + if (seq.length != 3) + throw new IllegalArgumentException ("not a PKCS #10 request"); + + data = seq [0].toByteArray (); // reusing this variable + certRequestInfo = seq[0].toByteArray(); // make a copy + id = AlgorithmId.parse (seq [1]); + sigData = seq [2].getBitString (); + + // + // Inner sequence: version, name, key, attributes + // + BigInt serial; + DerValue val; + + serial = seq [0].data.getInteger (); +/* + if (serial.toInt () != 0) + throw new IllegalArgumentException ("not PKCS #10 v1"); +*/ + + subject = new X500Name (seq [0].data); + + + byte val1[] = seq [0].data.getDerValue ().toByteArray(); + subjectPublicKeyInfo = X509Key.parse (new DerValue(val1)); + PublicKey publicKey = X509Key.parsePublicKey (new DerValue(val1)); + + String keystr = subjectPublicKeyInfo.toString(); + + // Cope with a somewhat common illegal PKCS #10 format + if (seq [0].data.available () != 0) + attributeSet = new PKCS10Attributes(seq [0].data); + else + attributeSet = new PKCS10Attributes(); + + // + // OK, we parsed it all ... validate the signature using the + // key and signature algorithm we found. + // temporary commented out + try { + String idName = id.getName (); + if(idName.equals("MD5withRSA")) + idName = "MD5/RSA"; + else if(idName.equals("MD2withRSA")) + idName = "MD2/RSA"; + else if(idName.equals("SHA1withRSA")) + idName = "SHA1/RSA"; + else if(idName.equals("SHA1withDSA")) + idName = "SHA1/DSA"; + + if (sigver) { + sig = Signature.getInstance(idName,"Mozilla-JSS"); + + sig.initVerify (publicKey); + sig.update (data); + if (!sig.verify (sigData)) + throw new SignatureException ("Invalid PKCS #10 signature"); + } + } catch (InvalidKeyException e) { + throw new SignatureException ("invalid key"); + } + } + + public PKCS10 (byte data []) + throws IOException, SignatureException, NoSuchAlgorithmException,java.security.NoSuchProviderException + { + this(data, true); + } + + /** + * Create the signed certificate request. This will later be + * retrieved in either string or binary format. + * + * @param requester identifies the signer (by X.500 name) + * and provides the private key used to sign. + * @exception IOException on errors. + * @exception CertificateException on certificate handling errors. + * @exception SignatureException on signature handling errors. + */ + public void encodeAndSign (X500Signer requester) + throws CertificateException, IOException, SignatureException + { + DerOutputStream out, scratch; + byte certificateRequestInfo []; + byte sig []; + + if (certificateRequest != null) + throw new SignatureException ("request is already signed"); + + subject = requester.getSigner (); + + /* + * Encode cert request info, wrap in a sequence for signing + */ + scratch = new DerOutputStream (); + scratch.putInteger (new BigInt (0)); // version zero + subject.encode (scratch); // X.500 name + subjectPublicKeyInfo.encode (scratch); // public key + attributeSet.encode (scratch); + + out = new DerOutputStream (); + out.write (DerValue.tag_Sequence, scratch); // wrap it! + certificateRequestInfo = out.toByteArray (); + scratch = out; + + /* + * Sign it ... + */ + requester.update (certificateRequestInfo, 0, + certificateRequestInfo.length); + sig = requester.sign (); + + /* + * Build guts of SIGNED macro + */ + requester.getAlgorithmId ().encode (scratch); // sig algorithm + scratch.putBitString (sig); // sig + + /* + * Wrap those guts in a sequence + */ + out = new DerOutputStream (); + out.write (DerValue.tag_Sequence, scratch); + certificateRequest = out.toByteArray (); + } + + + /** + * Returns the subject's name. + */ + public X500Name getSubjectName () + { return subject; } + + + /** + * Returns the subject's public key. + */ + public X509Key getSubjectPublicKeyInfo () + { return subjectPublicKeyInfo; } + + + /** + * Returns the additional attributes requested. + */ + public PKCS10Attributes getAttributes () + { return attributeSet; } + + /** + * Returns the encoded and signed certificate request as a + * DER-encoded byte array. + * + * @return the certificate request, or null if encodeAndSign() + * has not yet been called. + */ + public byte [] toByteArray () + { + return certificateRequest; + } + + + /** + * Prints an E-Mailable version of the certificate request on the print + * stream passed. The format is a common base64 encoded one, supported + * by most Certificate Authorities because Netscape web servers have + * used this for some time. Some certificate authorities expect some + * more information, in particular contact information for the web + * server administrator. + * + * @param out the print stream where the certificate request + * will be printed. + * @exception IOException when an output operation failed + * @exception SignatureException when the certificate request was + * not yet signed. + */ + public void print (PrintStream out) + throws IOException, SignatureException + { + if (certificateRequest == null) + throw new SignatureException ("Cert request was not signed"); + + + out.println ("-----BEGIN NEW CERTIFICATE REQUEST-----"); + out.println (com.netscape.osutil.OSUtil.BtoA(certificateRequest)); + out.println ("-----END NEW CERTIFICATE REQUEST-----"); + } + + /** + * Provides a short description of this request. + */ + public String toString () + { + return "[PKCS #10 certificate request:\n" + + subjectPublicKeyInfo.toString() + + " subject: <" + subject + ">" + "\n" + + " attributes: " + attributeSet.toString() + + "\n]"; + } + + /** + * Retrieve the PKCS10 CertificateRequestInfo as a byte array + */ + public byte[] getCertRequestInfo() + { + return certRequestInfo; + } + + private X500Name subject; + private X509Key subjectPublicKeyInfo; + private PKCS10Attributes attributeSet; + + private byte certificateRequest []; // signed + private byte certRequestInfo []; // inner content signed +} |