org.xipki.security.P10RequestGenerator.java Source code

Java tutorial

Introduction

Here is the source code for org.xipki.security.P10RequestGenerator.java

Source

/*
 *
 * This file is part of the XiPKI project.
 * Copyright (c) 2014 - 2015 Lijun Liao
 * Author: Lijun Liao
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License version 3
 * as published by the Free Software Foundation with the addition of the
 * following permission added to Section 15 as permitted in Section 7(a):
 * FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY
 * THE AUTHOR LIJUN LIAO. LIJUN LIAO DISCLAIMS THE WARRANTY OF NON INFRINGEMENT
 * OF THIRD PARTY RIGHTS.
 *
 * 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * The interactive user interfaces in modified source and object code versions
 * of this program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU Affero General Public License.
 *
 * You can be released from the requirements of the license by purchasing
 * a commercial license. Buying such a license is mandatory as soon as you
 * develop commercial activities involving the XiPKI software without
 * disclosing the source code of your own applications.
 *
 * For more information, please contact Lijun Liao at this
 * address: lijun.liao@gmail.com
 */

package org.xipki.security;

import java.io.IOException;
import java.security.cert.X509Certificate;
import java.util.List;
import java.util.Set;

import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.DERTaggedObject;
import org.bouncycastle.asn1.DERUTF8String;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.x500.DirectoryString;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.AccessDescription;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.asn1.x509.Extensions;
import org.bouncycastle.asn1.x509.GeneralName;
import org.bouncycastle.asn1.x509.GeneralNames;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.pkcs.PKCS10CertificationRequest;
import org.bouncycastle.pkcs.PKCS10CertificationRequestBuilder;
import org.xipki.common.CmpUtf8Pairs;
import org.xipki.common.util.CollectionUtil;
import org.xipki.common.util.X509Util;
import org.xipki.security.api.ConcurrentContentSigner;
import org.xipki.security.api.NoIdleSignerException;
import org.xipki.security.api.PasswordResolverException;
import org.xipki.security.api.SecurityFactory;
import org.xipki.security.api.SignerException;

/**
 * @author Lijun Liao
 */

public class P10RequestGenerator {

    public PKCS10CertificationRequest generateRequest(final SecurityFactory securityFactory,
            final String signerType, final String signerConf, final SubjectPublicKeyInfo subjectPublicKeyInfo,
            final String subject, final List<Extension> extensions)
            throws PasswordResolverException, SignerException {
        X500Name subjectDN = new X500Name(subject);
        return generateRequest(securityFactory, signerType, signerConf, subjectPublicKeyInfo, subjectDN,
                extensions);
    }

    public PKCS10CertificationRequest generateRequest(final SecurityFactory securityFactory,
            final String signerType, final String signerConf, final SubjectPublicKeyInfo subjectPublicKeyInfo,
            final X500Name subjectDN, final List<Extension> extensions)
            throws PasswordResolverException, SignerException {
        ConcurrentContentSigner signer = securityFactory.createSigner(signerType, signerConf,
                (X509Certificate[]) null);
        ContentSigner contentSigner;
        try {
            contentSigner = signer.borrowContentSigner();
        } catch (NoIdleSignerException e) {
            throw new SignerException(e.getMessage(), e);
        }
        try {
            return generateRequest(contentSigner, subjectPublicKeyInfo, subjectDN, extensions);
        } finally {
            signer.returnContentSigner(contentSigner);
        }
    }

    public PKCS10CertificationRequest generateRequest(final ContentSigner contentSigner,
            final SubjectPublicKeyInfo subjectPublicKeyInfo, final X500Name subjectDN,
            final List<Extension> extensions) {
        PKCS10CertificationRequestBuilder p10ReqBuilder = new PKCS10CertificationRequestBuilder(subjectDN,
                subjectPublicKeyInfo);
        if (CollectionUtil.isNotEmpty(extensions)) {
            Extensions _extensions = new Extensions(extensions.toArray(new Extension[0]));
            p10ReqBuilder.addAttribute(PKCSObjectIdentifiers.pkcs_9_at_extensionRequest, _extensions);
        }
        return p10ReqBuilder.build(contentSigner);
    }

    public static Extension createExtensionSubjectAltName(final List<String> taggedValues, final boolean critical)
            throws BadInputException {
        GeneralNames names = createGeneralNames(taggedValues);
        if (names == null) {
            return null;
        }

        try {
            return new Extension(Extension.subjectAlternativeName, critical, names.getEncoded());
        } catch (IOException e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }

    public static GeneralNames createGeneralNames(final List<String> taggedValues) throws BadInputException {
        if (CollectionUtil.isEmpty(taggedValues)) {
            return null;
        }

        int n = taggedValues.size();
        GeneralName[] names = new GeneralName[n];
        for (int i = 0; i < n; i++) {
            names[i] = createGeneralName(taggedValues.get(i));
        }
        return new GeneralNames(names);
    }

    public static Extension createExtensionSubjectInfoAccess(final List<String> accessMethodAndLocations,
            final boolean critical) throws BadInputException {
        if (CollectionUtil.isEmpty(accessMethodAndLocations)) {
            return null;
        }

        ASN1EncodableVector vector = new ASN1EncodableVector();
        for (String accessMethodAndLocation : accessMethodAndLocations) {
            vector.add(createAccessDescription(accessMethodAndLocation));
        }
        ASN1Sequence seq = new DERSequence(vector);
        try {
            return new Extension(Extension.subjectInfoAccess, critical, seq.getEncoded());
        } catch (IOException e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }

    public static AccessDescription createAccessDescription(final String accessMethodAndLocation)
            throws BadInputException {
        CmpUtf8Pairs pairs;
        try {
            pairs = new CmpUtf8Pairs(accessMethodAndLocation);
        } catch (IllegalArgumentException e) {
            throw new BadInputException("invalid accessMethodAndLocation " + accessMethodAndLocation);
        }

        Set<String> oids = pairs.getNames();
        if (oids == null || oids.size() != 1) {
            throw new BadInputException("invalid accessMethodAndLocation " + accessMethodAndLocation);
        }

        String accessMethodS = oids.iterator().next();
        String taggedValue = pairs.getValue(accessMethodS);
        ASN1ObjectIdentifier accessMethod = new ASN1ObjectIdentifier(accessMethodS);

        GeneralName location = createGeneralName(taggedValue);
        return new AccessDescription(accessMethod, location);
    }

    /**
     *
     * @param taggedValue [tag]value, and the value for tags otherName and ediPartyName is type=value.
     * @param modes
     * @return
     * @throws BadInputException
     */
    public static GeneralName createGeneralName(final String taggedValue) throws BadInputException {
        int tag = -1;
        String value = null;
        if (taggedValue.charAt(0) == '[') {
            int idx = taggedValue.indexOf(']', 1);
            if (idx > 1 && idx < taggedValue.length() - 1) {
                String tagS = taggedValue.substring(1, idx);
                try {
                    tag = Integer.parseInt(tagS);
                    value = taggedValue.substring(idx + 1);
                } catch (NumberFormatException e) {
                }
            }
        }

        if (tag == -1) {
            throw new BadInputException("invalid taggedValue " + taggedValue);
        }

        switch (tag) {
        case GeneralName.otherName: {
            int idxSep = value.indexOf("=");
            if (idxSep == -1 || idxSep == 0 || idxSep == value.length() - 1) {
                throw new BadInputException("invalid otherName " + value);
            }
            String otherTypeOid = value.substring(0, idxSep);
            ASN1ObjectIdentifier type = new ASN1ObjectIdentifier(otherTypeOid);
            String otherValue = value.substring(idxSep + 1);
            ASN1EncodableVector vector = new ASN1EncodableVector();
            vector.add(type);
            vector.add(new DERTaggedObject(true, 0, new DERUTF8String(otherValue)));
            DERSequence seq = new DERSequence(vector);
            return new GeneralName(GeneralName.otherName, seq);
        }
        case GeneralName.rfc822Name:
            return new GeneralName(tag, value);
        case GeneralName.dNSName:
            return new GeneralName(tag, value);
        case GeneralName.directoryName: {
            X500Name x500Name = X509Util.reverse(new X500Name(value));
            return new GeneralName(GeneralName.directoryName, x500Name);
        }
        case GeneralName.ediPartyName: {
            int idxSep = value.indexOf("=");
            if (idxSep == -1 || idxSep == value.length() - 1) {
                throw new BadInputException("invalid ediPartyName " + value);
            }
            String nameAssigner = idxSep == 0 ? null : value.substring(0, idxSep);
            String partyName = value.substring(idxSep + 1);
            ASN1EncodableVector vector = new ASN1EncodableVector();
            if (nameAssigner != null) {
                vector.add(new DERTaggedObject(false, 0, new DirectoryString(nameAssigner)));
            }
            vector.add(new DERTaggedObject(false, 1, new DirectoryString(partyName)));
            ASN1Sequence seq = new DERSequence(vector);
            return new GeneralName(GeneralName.ediPartyName, seq);
        }
        case GeneralName.uniformResourceIdentifier:
            return new GeneralName(tag, value);
        case GeneralName.iPAddress:
            return new GeneralName(tag, value);
        case GeneralName.registeredID:
            return new GeneralName(tag, value);
        default:
            throw new RuntimeException("unsupported tag " + tag);
        } // end switch(tag)
    }

}