package com.ideal.mdm.cert.service;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import java.security.SignatureException;
import java.security.cert.CertStoreException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.RSAPublicKeySpec;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Random;
import javax.security.auth.x500.X500Principal;
import org.apache.log4j.Logger;
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x500.X500NameStyle;
import org.bouncycastle.asn1.x509.BasicConstraints;
import org.bouncycastle.asn1.x509.ExtendedKeyUsage;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.asn1.x509.GeneralName;
import org.bouncycastle.asn1.x509.KeyPurposeId;
import org.bouncycastle.asn1.x509.KeyUsage;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.asn1.x509.X509Extension;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
import org.bouncycastle.crypto.params.RSAKeyParameters;
import org.bouncycastle.crypto.util.PublicKeyFactory;
import org.bouncycastle.openssl.PEMReader;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.bouncycastle.pkcs.PKCS10CertificationRequest;
import org.jscep.client.ClientException;
import org.jscep.transaction.FailInfo;
import org.jscep.transaction.OperationFailureException;
import org.jscep.transaction.TransactionException;
import com.ideal.mdm.cert.util.WinBCStyle;
import sun.misc.BASE64Decoder;
public class SCEPCertService {
protected static final Logger logger = Logger.getLogger(SCEPCertService.class);
private static PrivateKey priKey;
private static PublicKey pubKey;
private static X509Certificate ca;
private static X500Name issuer;
private static X500Name pollName;
private static BigInteger caSerial;
public static X509Certificate mainSignCSRProcedure(String b64DerCsr)
throws NoSuchAlgorithmException, SignatureException,
InvalidKeyException, NoSuchProviderException, ClientException,
OperatorCreationException, TransactionException,
CertificateException, CertStoreException, IOException, InvalidKeySpecException {
init();
BASE64Decoder decoder = new BASE64Decoder();
byte[] derCsr;
PublicKey csrPubKey;
derCsr=decoder.decodeBuffer(b64DerCsr);
csrPubKey = geneneratePublicKey(derCsr);
X509Certificate issued=doEnrol(csrPubKey);
return issued;
//PemReader pemReader = null;
/*try {
FileReader fileReader = new FileReader(csrPath);
pemReader = new PemReader(fileReader);
} catch (FileNotFoundException e1) {
e1.printStackTrace();
logger.debug(e1.getMessage());
}*/
/*PKCS10CertificationRequest csr = null;
try {
csr = new PKCS10CertificationRequest(pemReader.readPemObject()
.getContent());
} catch (IOException e) {
e.printStackTrace();
logger.debug(e.getMessage());
}*/
}
protected static X509Certificate doEnrol(PublicKey csrPubKey) throws OperationFailureException {
try {
//X500Name origin_subject = X500Name.getInstance(csr.getSubject());
/*if (subject.equals(pollName)) {
return Collections.emptyList();
}*/
//logger.debug(origin_subject.toString());
//new X500Name();
// PrintableString ps=new PrintableString("");
//X500Principal
X500Name new_subject=new X500Name(WinBCStyle.INSTANCE,"CN=IdealMobile01");
//new_subject instanceof PrintableString;
//new_subject.getRDNs()[0].
//PublicKey pubKey = CertificationRequestUtils.getPublicKey(csr);
X509Certificate issued = generateCertificate(csrPubKey, new_subject, issuer,
getSerial());
return issued;
} catch (Exception e) {
logger.debug(e.getMessage());
throw new OperationFailureException(FailInfo.badRequest);
}
}
private static X509Certificate generateCertificate(PublicKey pubKey,
X500Name subject, X500Name issuer, BigInteger serial)
throws Exception {
Calendar cal = GregorianCalendar.getInstance();
cal.add(Calendar.YEAR, -1);
Date notBefore = cal.getTime();
cal.add(Calendar.YEAR, 2);
Date notAfter = cal.getTime();
JcaX509v3CertificateBuilder builder = new JcaX509v3CertificateBuilder(
issuer, serial, notBefore, notAfter, subject, pubKey);
builder.addExtension(X509Extension.basicConstraints, true,
new BasicConstraints(false));
// ExtendedKeyUsage anyExtendedKeyUsage = new ExtendedKeyUsage(KeyPurposeId.anyExtendedKeyUsage);
// X509Extension anyExtendedKeyUsageExtension = new X509Extension(false, new DEROctetString(anyExtendedKeyUsage));
// builder.addExtension(X509Extension.extendedKeyUsage, true, anyExtendedKeyUsageExtension.getParsedValue());
ASN1EncodableVector asn1ExtKeyUsage = new ASN1EncodableVector();
// asn1ExtKeyUsage.add(KeyPurposeId.anyExtendedKeyUsage); // 任何用途
// asn1ExtKeyUsage.add(KeyPurposeId.id_kp_serverAuth); // SSL的服务器认证
asn1ExtKeyUsage.add(KeyPurposeId.id_kp_clientAuth); // SSL的客户端认证
// asn1ExtKeyUsage.add(KeyPurposeId.id_kp_codeSigning); // 代码签名
// asn1ExtKeyUsage.add(KeyPurposeId.id_kp_codeSigning); // 代码签名
// asn1ExtKeyUsage.add(KeyPurposeId.id_kp_ipsecEndSystem); //
// asn1ExtKeyUsage.add(KeyPurposeId.id_kp_ipsecTunnel); //
// asn1ExtKeyUsage.add(KeyPurposeId.id_kp_ipsecUser); //
// asn1ExtKeyUsage.add(KeyPurposeId.id_kp_timeStamping); // 时间戳 认证
// asn1ExtKeyUsage.add(KeyPurposeId.id_kp_OCSPSigning); // ocsp证书认证
// asn1ExtKeyUsage.add(KeyPurposeId.id_kp_smartcardlogon);
// asn1ExtKeyUsage.add(new GeneralName(GeneralName.dNSName,"ejbca.linyiheng.cn"));
ExtendedKeyUsage extendedKeyUsage = new ExtendedKeyUsage(new DERSequence(asn1ExtKeyUsage));
builder.addExtension(Extension.extendedKeyUsage, true, extendedKeyUsage);
//builder.addExtension(Extension.subjectAlternativeName, true, arg2)
KeyUsage keyUsage= new KeyUsage(KeyUsage.digitalSignature);
X509Extension keyUsageExtension = new X509Extension(true, new DEROctetString(keyUsage));
builder.addExtension(X509Extension.keyUsage, true, keyUsageExtension.getParsedValue());
ContentSigner signer;
try {
signer = new JcaContentSignerBuilder("SHA1withRSA").build(priKey);
} catch (OperatorCreationException e) {
logger.debug(e.getMessage());
throw new Exception(e);
}
X509CertificateHolder holder = builder.build(signer);
X509Certificate cert = new JcaX509CertificateConverter()
.getCertificate(holder);
//savePEMFile("/root/certificate/client.crt", cert);
logger.debug("Cert's issuer DN is: "+cert);
return cert;
}
// private static void savePEMFile(String path, Object obj) throws IOException {
// FileWriter fw = new FileWriter(path);
// PEMWriter writer = new PEMWriter(fw);
// writer.writeObject(obj);
// writer.close();
// }
public static void init() {
try {
ca = loadLocalCertificate();
//BouncyCastleHelpers.toX500Name(ca.getSubjectX500Principal());
//new X500Name((ASN1Sequence) ca.getIssuerDN());
//new X500Name();
//new X500Name(ca.getSubjectX500Principal().RFC1779);
// logger.debug("CA's issuer is :"+ ca.getSubjectX500Principal().getName());
// logger.debug("CA's issuer is :"+ ca.getSubjectX500Principal().getName(X500Principal.RFC1779));
// logger.debug("CA's issuer is :"+ ca.getSubjectX500Principal().getName(X500Principal.RFC2253));
// logger.debug("CA's issuer is :"+ ca.getSubjectX500Principal().getName(X500Principal.CANONICAL));
issuer = new X500Name(WinBCStyle.INSTANCE,"C=CN,ST=SH,L=SH,O=Ideal,OU=Ideal,CN=host.linyiheng.cn,[email protected]");
//pollName = new X500Name("CN=Poll2");
caSerial = BigInteger.TEN;
BufferedReader br = new BufferedReader(new InputStreamReader(
new SCEPCertService().getClass().getResourceAsStream("/ca.key")));
PEMReader localPEMReader=new PEMReader(br);
// PEMReader localPEMReader = new PEMReader(br, new PasswordFinder() {
//
// public char[] getPassword() {
// return "1111".toCharArray();
// }
//
// });
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
priKey = ((KeyPair) localPEMReader.readObject()).getPrivate();
localPEMReader.close();
br.close();
pubKey = ca.getPublicKey();
} catch (IOException e) {
logger.debug(e.getMessage());
e.printStackTrace();
}
}
public static X509Certificate loadLocalCertificate() {
try {
InputStream ica = new SCEPCertService().getClass().getResourceAsStream("/ca.crt");
CertificateFactory certFactory = CertificateFactory
.getInstance("X.509");
ca = (X509Certificate) certFactory.generateCertificate(ica);
} catch (Exception e) {
logger.debug(e.getMessage());
e.printStackTrace();
}
return ca;
}
private static BigInteger getSerial() {
Random rnd = new Random();
return BigInteger.valueOf(Math.abs(rnd.nextLong()) + 1);
}
public static PublicKey geneneratePublicKey(byte[] key) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
PKCS10CertificationRequest pkcs10CertReq=new PKCS10CertificationRequest(key);
SubjectPublicKeyInfo pkInfo = pkcs10CertReq.getSubjectPublicKeyInfo();
RSAKeyParameters rsa = (RSAKeyParameters) PublicKeyFactory.createKey(pkInfo);
RSAPublicKeySpec rsaSpec = new RSAPublicKeySpec(rsa.getModulus(), rsa.getExponent());
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
return keyFactory.generatePublic(rsaSpec);
}
}
通过修改默认的BCStyle可以修改subject与issuer的名称类型。具体可以通过grepcode了解其中源码。