org.bouncycastle.jce.netscape.NetscapeCertRequest.java Source code

Java tutorial

Introduction

Here is the source code for org.bouncycastle.jce.netscape.NetscapeCertRequest.java

Source

package org.bouncycastle.jce.netscape;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Signature;
import java.security.SignatureException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;

import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1Encoding;
import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.ASN1Object;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DERBitString;
import org.bouncycastle.asn1.DERIA5String;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;

/**
 *
 * 
 * Handles NetScape certificate request (KEYGEN), these are constructed as:
 * <pre>
 *   SignedPublicKeyAndChallenge ::= SEQUENCE {
 *     publicKeyAndChallenge    PublicKeyAndChallenge,
 *     signatureAlgorithm       AlgorithmIdentifier,
 *     signature                BIT STRING
 *   }
 * </pre>
 *
 * PublicKey's encoded-format has to be X.509.
 *
 **/
public class NetscapeCertRequest extends ASN1Object {
    AlgorithmIdentifier sigAlg;
    AlgorithmIdentifier keyAlg;
    byte sigBits[];
    String challenge;
    DERBitString content;
    PublicKey pubkey;

    private static ASN1Sequence getReq(byte[] r) throws IOException {
        ASN1InputStream aIn = new ASN1InputStream(new ByteArrayInputStream(r));

        return ASN1Sequence.getInstance(aIn.readObject());
    }

    public NetscapeCertRequest(byte[] req) throws IOException {
        this(getReq(req));
    }

    public NetscapeCertRequest(ASN1Sequence spkac) {
        try {

            //
            // SignedPublicKeyAndChallenge ::= SEQUENCE {
            //    publicKeyAndChallenge    PublicKeyAndChallenge,
            //    signatureAlgorithm    AlgorithmIdentifier,
            //    signature        BIT STRING
            // }
            //
            if (spkac.size() != 3) {
                throw new IllegalArgumentException("invalid SPKAC (size):" + spkac.size());
            }

            sigAlg = AlgorithmIdentifier.getInstance(spkac.getObjectAt(1));
            sigBits = ((DERBitString) spkac.getObjectAt(2)).getOctets();

            //
            // PublicKeyAndChallenge ::= SEQUENCE {
            //    spki            SubjectPublicKeyInfo,
            //    challenge        IA5STRING
            // }
            //
            ASN1Sequence pkac = (ASN1Sequence) spkac.getObjectAt(0);

            if (pkac.size() != 2) {
                throw new IllegalArgumentException("invalid PKAC (len): " + pkac.size());
            }

            challenge = ((DERIA5String) pkac.getObjectAt(1)).getString();

            //this could be dangerous, as ASN.1 decoding/encoding
            //could potentially alter the bytes
            content = new DERBitString(pkac);

            SubjectPublicKeyInfo pubkeyinfo = SubjectPublicKeyInfo.getInstance(pkac.getObjectAt(0));

            X509EncodedKeySpec xspec = new X509EncodedKeySpec(new DERBitString(pubkeyinfo).getBytes());

            keyAlg = pubkeyinfo.getAlgorithm();
            pubkey = KeyFactory.getInstance(keyAlg.getAlgorithm().getId(), "BC").generatePublic(xspec);

        } catch (Exception e) {
            throw new IllegalArgumentException(e.toString());
        }
    }

    public NetscapeCertRequest(String challenge, AlgorithmIdentifier signing_alg, PublicKey pub_key)
            throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchProviderException {

        this.challenge = challenge;
        sigAlg = signing_alg;
        pubkey = pub_key;

        ASN1EncodableVector content_der = new ASN1EncodableVector();
        content_der.add(getKeySpec());
        //content_der.add(new SubjectPublicKeyInfo(sigAlg, new RSAPublicKeyStructure(pubkey.getModulus(), pubkey.getPublicExponent()).getDERObject()));
        content_der.add(new DERIA5String(challenge));

        try {
            content = new DERBitString(new DERSequence(content_der));
        } catch (IOException e) {
            throw new InvalidKeySpecException("exception encoding key: " + e.toString());
        }
    }

    public String getChallenge() {
        return challenge;
    }

    public void setChallenge(String value) {
        challenge = value;
    }

    public AlgorithmIdentifier getSigningAlgorithm() {
        return sigAlg;
    }

    public void setSigningAlgorithm(AlgorithmIdentifier value) {
        sigAlg = value;
    }

    public AlgorithmIdentifier getKeyAlgorithm() {
        return keyAlg;
    }

    public void setKeyAlgorithm(AlgorithmIdentifier value) {
        keyAlg = value;
    }

    public PublicKey getPublicKey() {
        return pubkey;
    }

    public void setPublicKey(PublicKey value) {
        pubkey = value;
    }

    public boolean verify(String challenge)
            throws NoSuchAlgorithmException, InvalidKeyException, SignatureException, NoSuchProviderException {
        if (!challenge.equals(this.challenge)) {
            return false;
        }

        //
        // Verify the signature .. shows the response was generated
        // by someone who knew the associated private key
        //
        Signature sig = Signature.getInstance(sigAlg.getAlgorithm().getId(), "BC");
        sig.initVerify(pubkey);
        sig.update(content.getBytes());

        return sig.verify(sigBits);
    }

    public void sign(PrivateKey priv_key) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException,
            NoSuchProviderException, InvalidKeySpecException {
        sign(priv_key, null);
    }

    public void sign(PrivateKey priv_key, SecureRandom rand) throws NoSuchAlgorithmException, InvalidKeyException,
            SignatureException, NoSuchProviderException, InvalidKeySpecException {
        Signature sig = Signature.getInstance(sigAlg.getAlgorithm().getId(), "BC");

        if (rand != null) {
            sig.initSign(priv_key, rand);
        } else {
            sig.initSign(priv_key);
        }

        ASN1EncodableVector pkac = new ASN1EncodableVector();

        pkac.add(getKeySpec());
        pkac.add(new DERIA5String(challenge));

        try {
            sig.update(new DERSequence(pkac).getEncoded(ASN1Encoding.DER));
        } catch (IOException ioe) {
            throw new SignatureException(ioe.getMessage());
        }

        sigBits = sig.sign();
    }

    private ASN1Primitive getKeySpec()
            throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchProviderException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();

        ASN1Primitive obj = null;
        try {

            baos.write(pubkey.getEncoded());
            baos.close();

            ASN1InputStream derin = new ASN1InputStream(new ByteArrayInputStream(baos.toByteArray()));

            obj = derin.readObject();
        } catch (IOException ioe) {
            throw new InvalidKeySpecException(ioe.getMessage());
        }
        return obj;
    }

    public ASN1Primitive toASN1Primitive() {
        ASN1EncodableVector spkac = new ASN1EncodableVector();
        ASN1EncodableVector pkac = new ASN1EncodableVector();

        try {
            pkac.add(getKeySpec());
        } catch (Exception e) {
            //ignore
        }

        pkac.add(new DERIA5String(challenge));

        spkac.add(new DERSequence(pkac));
        spkac.add(sigAlg);
        spkac.add(new DERBitString(sigBits));

        return new DERSequence(spkac);
    }
}