`
dongpublic
  • 浏览: 8037 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

BC组装证书

    博客分类:
  • PKI
阅读更多
package cn.dong.cert;

import java.util.Map;
import java.util.Date;
import java.util.Vector;
import java.util.HashMap;
import java.util.Hashtable;
import java.math.BigInteger;
import java.security.KeyPair;
import java.security.Security;
import java.security.PublicKey;
import java.security.Signature;
import java.io.FileOutputStream;
import java.security.PrivateKey;
import org.bouncycastle.asn1.DERSet;
import java.security.KeyPairGenerator;
import org.bouncycastle.asn1.DERUTCTime;
import org.bouncycastle.asn1.DERInteger;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.DERBitString;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.KeyUsage;
import org.bouncycastle.asn1.x509.Attribute;
import org.bouncycastle.asn1.DERTaggedObject;
import org.bouncycastle.util.encoders.Base64;
import org.bouncycastle.asn1.x509.GeneralName;
import org.bouncycastle.asn1.x509.GeneralNames;
import org.bouncycastle.asn1.x509.CRLDistPoint;
import org.bouncycastle.asn1.x509.KeyPurposeId;
import org.bouncycastle.asn1.DERPrintableString;
import org.bouncycastle.asn1.DERGeneralizedTime;
import org.bouncycastle.asn1.x509.GeneralSubtree;
import org.bouncycastle.asn1.x509.PolicyMappings;
import org.bouncycastle.asn1.DERObjectIdentifier;
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.x509.X509Extensions;
import org.bouncycastle.asn1.x509.NameConstraints;
import org.bouncycastle.asn1.x509.ExtendedKeyUsage;
import org.bouncycastle.asn1.x509.BasicConstraints;
import org.bouncycastle.asn1.x509.AccessDescription;
import org.bouncycastle.asn1.x509.PolicyInformation;
import org.bouncycastle.asn1.x509.DistributionPoint;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.SubjectKeyIdentifier;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.asn1.x509.DistributionPointName;
import org.bouncycastle.asn1.x509.PrivateKeyUsagePeriod;
import org.bouncycastle.asn1.x509.AuthorityKeyIdentifier;
import org.bouncycastle.asn1.x509.TBSCertificateStructure;
import org.bouncycastle.asn1.x509.X509ExtensionsGenerator;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.asn1.x509.X509CertificateStructure;
import org.bouncycastle.jce.provider.X509CertificateObject;
import org.bouncycastle.asn1.x509.V3TBSCertificateGenerator;
import org.bouncycastle.asn1.x509.SubjectDirectoryAttributes;

public class CertService {

	public static void main(String[] agrs) throws Exception {
		
		Security.addProvider(new BouncyCastleProvider()); // 加载BC Provider
		
		int certValidity = 1; // 证书有效期
		
		X500Name subject = new X500Name("CN=root,O=O,OU=OU"); //证书主题
		 
		X500Name issuer = new X500Name("CN=root,O=O,OU=OU");  //证书颁发者
		
		KeyPair kp = genKeyPair("RSA"); // 产生RSA算法密钥对
		
		PrivateKey priKey = kp.getPrivate();
		PublicKey pubKey = kp.getPublic();
		
		// 签发根证书
		TBSCertificateStructure tbsCert = createTbsCert(certValidity, issuer,
				subject, pubKey, pubKey);
		
		// 签名算法
		AlgorithmIdentifier alg = tbsCert.getSignature();
		
		// 对证书主题进行签名
		byte[] signData = sign(pubKey.getAlgorithm(), tbsCert.getEncoded(),
				priKey);

		// 构建证书
		ASN1EncodableVector asn1Vector = new ASN1EncodableVector();
		asn1Vector.add(tbsCert.getDERObject());
		asn1Vector.add(alg.getDERObject());
		asn1Vector.add(new DERBitString(signData));
		X509CertificateObject cert = new X509CertificateObject(
				new X509CertificateStructure(new DERSequence(asn1Vector)));
		
		// 打印证书的base64编码
		System.out.println("certBuf:"
				+ new String(Base64.encode(cert.getEncoded())));
		cert.verify(cert.getPublicKey()); // 验证签名,无异常验签通过

		FileOutputStream fos = new FileOutputStream("cert.cer");
		fos.write(cert.getEncoded());
		fos.flush();
		fos.close();
	}

	// 创建证书
	public static TBSCertificateStructure createTbsCert(int certValidity,
			X500Name IssuerName, X500Name subjectName, PublicKey certPubKey,
			PublicKey issuerKey) throws Exception {
		// 证书有效期
		Date notBefore = new Date();
		long validity = certValidity * 1000 * 60 * 60 * 24;
		Date notAfter = new Date(notBefore.getTime() + validity);

		// 证书公钥信息
		SubjectPublicKeyInfo pubInfo = SubjectPublicKeyInfo
				.getInstance(certPubKey.getEncoded());

		// 组装证书主体
		V3TBSCertificateGenerator genCert = new V3TBSCertificateGenerator();
		genCert.setStartDate(new DERUTCTime(notBefore));
		genCert.setSubject(new X500Name("CN=root,O=O,OU=OU"));
		genCert.setIssuer(new X500Name("CN=root,O=O,OU=OU"));
		genCert.setEndDate(new DERUTCTime(notAfter));
		genCert.setSerialNumber(new DERInteger((int) System.currentTimeMillis()));
		genCert.setSubjectPublicKeyInfo(pubInfo);
		genCert.setSignature(new AlgorithmIdentifier("1.2.840.113549.1.1.5")); // SHA1withRSA
		X509Extensions exts = genCertExtensions(issuerKey, certPubKey); // 创建证书扩展项
		genCert.setExtensions(exts);

		return genCert.generateTBSCertificate();
	}

	@SuppressWarnings("deprecation")
	public static X509Extensions genCertExtensions(PublicKey issuerKey,
			PublicKey subjectKey) throws Exception {
		X509ExtensionsGenerator extGen = new X509ExtensionsGenerator();

		/**
		 * 基本用途限制
		 * 
		 * BasicConstraints := SEQUENCE { cA BOOLEAN DEFAULT FALSE, 是否是CA证书
		 * pathLenConstraint INTEGER (0..MAX) OPTIONAL 证书链长度约束 }
		 */
		BasicConstraints basicConstraints = new BasicConstraints(false, 0);
		extGen.addExtension(X509Extensions.BasicConstraints, true,
				basicConstraints);

		/**
		 * 密钥用法 The KeyUsage object.
		 * 
		 *  id-ce-keyUsage OBJECT IDENTIFIER ::=  { id-ce 15 }
		 * 
		 *  KeyUsage ::= BIT STRING {
		 *   digitalSignature (0), 数据验签:除了签发证书/签发CRL之外的各种数字签名操作,
		 *     数据完整性、身份鉴别、数据源鉴别。检查算法可以做签名  digitalSignature位被断
		 *     言,当主题公开密钥用一数字的签名算法来支持安全 服务而非抗抵赖性(位1)、签名
		 *     证书(位5)或者签名撤销信息(位6) 的时候。数字的签名算法常常为实体和数据起源
		 *     (做)完整性验证。
		 *     
		 *   nonRepudiation   (1), 不可抵赖性:证书对应的私钥,用于生成非否认的证据,证书
		 *      用于验证非否认证据。
		 *      
		 *   keyEncipherment  (2), 密钥加密:用于加密传输其他的密钥。检查可以加密密钥
		 *        keyEncipherment位被断言,当主题公开密钥被用于密钥传输的时候。例如,当一
		 *        RSA密钥用于密钥管理时候,那么这位将被断言。
		 *        
		 *   dataEncipherment (3), 数据加密:用于直接加解密应用数据,
		 *     通常都是公钥->对称密钥->应用数据。一般很少用这种方式的应用,因为:在密钥长度
		 *     安全的情况下,公钥密钥计算都是慢于对称密钥计算。检查可以加密数据  当主题公开密
		 *     钥用于(除了密码学的密钥)将用户数据加密使用的时候,dataEncipherment位被断言。
		 *   keyAgreement     (4), 密钥协商:在通信方之间协商对称密钥,例如:TLS、
		 *      Diffie-Hellman的密钥协商。不同于keyEncipherment. KeyEncipherment是直接对
		 *      Session Key进行加密  KeyAgreement是协商,别公钥加密的数据并不是直接作为密钥,
		 *      而是经过了一个多次步骤的过程,再导出Session Key。
		 *      
		 *   keyCertSign      (5), 签发证书:用于签发CA证书。 keyAgreement位被断言,当主题
		 *       公开密钥为用于密钥协议的时候。例如,当一Diffie Hellman密钥是要为密钥管理被使
		 *       用的时候,那么这位将被断言。
		 *     
		 *   cRLSign          (6), 签发crl:签发CRL,CA或者CRL Issuer
		 *     
		 *   encipherOnly     (7), 证书公钥在密钥协商过程中,仅仅进行加密计算,配合
		 *       KeyAgreement用法才有意义
		 *     
		 *   decipherOnly     (8) }证书公钥在密钥协商过程中,仅仅进行解密计算,配合
		 *       KeyAgreement用法才有意义
		 *  }
		 * 
		 */

		int usage = KeyUsage.digitalSignature;
		usage += KeyUsage.nonRepudiation;
		usage += KeyUsage.keyEncipherment;
		usage += KeyUsage.dataEncipherment;
		usage += KeyUsage.keyAgreement;
		usage += KeyUsage.keyCertSign;
		usage += KeyUsage.cRLSign;
		usage += KeyUsage.encipherOnly;
		usage += KeyUsage.decipherOnly;

		KeyUsage keyUsage = new KeyUsage(usage);

		extGen.addExtension(X509Extensions.KeyUsage, true, keyUsage);

		/**
		 * 增强型密钥用法 The extendedKeyUsage object.
		 * 
		 * <pre>
		 *      extendedKeyUsage ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId
		 * </pre>
		 */
		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_emailProtection); // 电子邮件的加解密、签名等
		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_dvcs);
		 * asn1ExtKeyUsage.add(KeyPurposeId.id_kp_sbgpCertAAServerAuth);
		 * asn1ExtKeyUsage.add(KeyPurposeId.id_kp_scvp_responder);
		 * asn1ExtKeyUsage.add(KeyPurposeId.id_kp_eapOverPPP);
		 * asn1ExtKeyUsage.add(KeyPurposeId.id_kp_eapOverLAN);
		 * asn1ExtKeyUsage.add(KeyPurposeId.id_kp_scvpServer);
		 * asn1ExtKeyUsage.add(KeyPurposeId.id_kp_scvpClient);
		 * asn1ExtKeyUsage.add(KeyPurposeId.id_kp_ipsecIKE);
		 * asn1ExtKeyUsage.add(KeyPurposeId.id_kp_capwapAC);
		 * asn1ExtKeyUsage.add(KeyPurposeId.id_kp_capwapWTP);
		 */
		asn1ExtKeyUsage.add(KeyPurposeId.id_kp_smartcardlogon);

		ExtendedKeyUsage extendedKeyUsage = new ExtendedKeyUsage(
				new DERSequence(asn1ExtKeyUsage));

		extGen.addExtension(X509Extensions.ExtendedKeyUsage, true,
				extendedKeyUsage);

		/**
		 * 证书撤销:已证书扩展的形式,给出了“检查本证书所需要的CRL文件,到上面地方获取” CRL
		 * DP中的信息是有多个DisributionPoint组成:每个DisributionPoint都存放CRL,
		 * CA可以在多个地方存放CRL
		 * 
		 * crl Produce an object suitable for an ASN1OutputStream.
		 * 
		 * <pre>
		 * CRLDistPoint ::= SEQUENCE SIZE {1..MAX} OF DistributionPoint
		 * </pre>
		 * 
		 * -- CRL distribution points extension OID and syntax
		 * 
		 * id-ce-cRLDistributionPoints OBJECT IDENTIFIER ::= {id-ce 31}
		 * 
		 * CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint
		 * 
		 * DistributionPoint ::= SEQUENCE { distributionPoint [0]
		 * DistributionPointName OPTIONAL, reasons [1] ReasonFlags OPTIONAL,
		 * cRLIssuer [2] GeneralNames OPTIONAL }
		 * 
		 * DistributionPointName ::= CHOICE { fullName [0] GeneralNames,
		 * nameRelativeToCRLIssuer [1] RelativeDistinguishedName }
		 */
		Map<Integer, String> map = new HashMap<Integer, String>();
		// map.put(GeneralName.otherName, "cn=otherName");
		map.put(GeneralName.rfc822Name, "cn=rfc822Name");
		map.put(GeneralName.dNSName, "192.168.30.241");
		// map.put(GeneralName.x400Address, "cn=x400Address");
		map.put(GeneralName.directoryName, "cn=root");
		// map.put(GeneralName.ediPartyName, "cn=ediPartyName");
		map.put(GeneralName.uniformResourceIdentifier, "http://certService/crl");
		map.put(GeneralName.iPAddress, "192.168.30.24");
		map.put(GeneralName.registeredID, "1.1.0.2.1");

		DistributionPoint[] dps = new DistributionPoint[map.size()];
		int i = 0;
		for (int key : map.keySet()) {
			GeneralName gn = null;
			if (key == GeneralName.otherName || key == GeneralName.ediPartyName) {
				continue;
			} else if (key == GeneralName.x400Address) {
				continue;
			} else {
				gn = new GeneralName(key, map.get(key));
			}

			GeneralNames gns = new GeneralNames(gn);
			DistributionPointName dpn = new DistributionPointName(gns);
			DistributionPoint dp = new DistributionPoint(dpn, null, null);
			dps[i] = dp;
			i++;
		}

		CRLDistPoint crlDistPoint = new CRLDistPoint(dps);

		extGen.addExtension(X509Extensions.CRLDistributionPoints, true,
				crlDistPoint);

		/**
		 * 增量crl Produce an object suitable for an ASN1OutputStream.
		 * 
		 * <pre>
		 * CRLDistPoint ::= SEQUENCE SIZE {1..MAX} OF DistributionPoint
		 * </pre>
		 */

		extGen.addExtension(X509Extensions.FreshestCRL, false, crlDistPoint);
		/**
		 * 主题备用名称
		 */
		GeneralName subjectAlternativeName = new GeneralName(
				GeneralName.directoryName, map.get(GeneralName.directoryName));
		extGen.addExtension(X509Extensions.SubjectAlternativeName, false,
				new DERSequence(subjectAlternativeName));

		/**
		 * 颁发者备用名称 : 放置签发者的各种不同的命名,map 是各种名称形式
		 */
		GeneralName issuerAlternativeName = new GeneralName(
				GeneralName.directoryName, map.get(GeneralName.directoryName));
		extGen.addExtension(X509Extensions.IssuerAlternativeName, false,
				new DERSequence(issuerAlternativeName));

		/**
		 * 密钥周期 : 对应私钥的使用期限
		 * 
		 * <pre>
		 *    PrivateKeyUsagePeriod ::= SEQUENCE {
		 *      notBefore       [0]     GeneralizedTime OPTIONAL,
		 *      notAfter        [1]     GeneralizedTime OPTIONAL }
		 * </pre>
		 */
		Date notAfter = new Date();
		Date notBefter = new Date();
		notBefter.setYear(notAfter.getYear() + 10);
		DERGeneralizedTime notAfterKey = new DERGeneralizedTime(notAfter);
		DERGeneralizedTime notBefterKey = new DERGeneralizedTime(notBefter);

		DERTaggedObject dtoNotBefterKey = new DERTaggedObject(false, 0,
				notBefterKey);
		DERTaggedObject dtoNotAfterKey = new DERTaggedObject(false, 1,
				notAfterKey);

		ASN1EncodableVector aevPriKeyUsagePeriod = new ASN1EncodableVector();
		aevPriKeyUsagePeriod.add(dtoNotBefterKey);
		aevPriKeyUsagePeriod.add(dtoNotAfterKey);
		PrivateKeyUsagePeriod pkup = PrivateKeyUsagePeriod
				.getInstance(new DERSequence(aevPriKeyUsagePeriod));
		extGen.addExtension(X509Extensions.PrivateKeyUsagePeriod, false, pkup);

		/**
		 * 策略限制 PolicyConstraints ::= SEQUENCE { requireExplicitPolicy [0]
		 * SkipCerts OPTIONAL, inhibitPolicyMapping [1] SkipCerts OPTIONAL }
		 */

		int requireExplicitPolicy = 10; // 表明额外的证书的数量
		int inhibitPolicyMapping = 10; // 应用程序支持数量
		ASN1EncodableVector pcVector = new ASN1EncodableVector();
		pcVector.add(new DERTaggedObject(false, 0, new DERInteger(
				requireExplicitPolicy)));
		pcVector.add(new DERTaggedObject(false, 1, new DERInteger(
				inhibitPolicyMapping)));

		extGen.addExtension(X509Extensions.PolicyConstraints, false,
				new DERSequence(pcVector));

		/**
		 * 禁止任何策略:
		 * 扩展项的值是整数N,N表示:在证书路径中,本证书之下的N个证书可带有Any-Policy的证书
		 * (N+1之下的证书就不能有Any-policy)
		 * 
		 * id-ce-inhibitAnyPolicy OBJECT IDENTIFIER ::= { id-ce 54 }
		 * 
		 * InhibitAnyPolicy ::= SkipCerts
		 * 
		 * SkipCerts ::= INTEGER (0..MAX)
		 */
		int inhibitAnyPolicy = 10;
		extGen.addExtension(X509Extensions.InhibitAnyPolicy, false,
				new DERInteger(inhibitAnyPolicy));

		/**
		 * 策略映射 扩展项仅仅存在于交叉证书中,说明了不同CA域之间的CP等级的相互映射关系
		 * 
		 * PolicyMappings ::= SEQUENCE SIZE (1..MAX) OF SEQUENCE {
		 * issuerDomainPolicy CertPolicyId, subjectDomainPolicy CertPolicyId }
		 */
		Hashtable<String, String> policyHashMap = new Hashtable<String, String>();
		policyHashMap.put("1.1.1.2.3.1", "1.1.1.2.3.4");
		policyHashMap.put("1.1.1.2.3.2", "1.1.1.2.3.5");

		PolicyMappings pms = new PolicyMappings(policyHashMap);

		extGen.addExtension(X509Extensions.PolicyMappings, false, pms);

		/**
		 * 使用者密钥标示符 SubjectKeyIdentifier ::= KeyIdentifier
		 */
		extGen.addExtension(
				X509Extensions.SubjectKeyIdentifier,
				false,
				new SubjectKeyIdentifier(SubjectPublicKeyInfo
						.getInstance(subjectKey.getEncoded())));
		/**
		 * 颁发者密钥标示符 IssuerKeyIdentifier ::= KeyIdentifier
		 */

		extGen.addExtension(
				X509Extensions.AuthorityKeyIdentifier,
				false,
				new AuthorityKeyIdentifier(SubjectPublicKeyInfo
						.getInstance(subjectKey.getEncoded())));
		/**
		 * 主题目录属性 原则上可以加入与Subject有关信息 因为使用了Atrribute Type的OID的、然后说明相对应的值
		 */
		// http://asn1.elibel.tm.fr/cgi-bin/oid/display?oid=1.3.6.1.5.5.7.9&action=display
		// PKIX personal data gender
		String genderOidStr = "1.3.6.1.5.5.7.9.4";

		// PKIX personal data dateOfBirth
		String dateOfBirthOidStr = "1.3.6.1.5.5.7.9.1";

		// 2.5.4.20 - id-at-telephoneNumber
		// http://www.alvestrand.no/objectid/2.5.4.html
		String streetAddressOidStr = "2.5.4.9";

		String telephoneNumberOidStr = "2.5.4.20";
		// http://oid.elibel.tm.fr/0.9.2342.19200300.100.1.41
		String mobileTelephoneNumberOidStr = "0.9.2342.19200300.100.1.41";

		Vector<Attribute> attributes = new Vector<Attribute>();

		Attribute genderAttribute = new Attribute(new DERObjectIdentifier(
				genderOidStr), new DERSet(new DERPrintableString(
				"汉族".getBytes("UTF-8"))));
		Attribute dateOfBirthAttribute = new Attribute(new DERObjectIdentifier(
				genderOidStr), new DERSet(new DERPrintableString(
				"1992-02-20".getBytes("UTF-8"))));
		Attribute streetAddressAttribute = new Attribute(
				new DERObjectIdentifier(genderOidStr),
				new DERSet(new DERPrintableString("北京市大王庄胡同13号"
						.getBytes("UTF-8"))));
		Attribute telephoneNumberAttribute = new Attribute(
				new DERObjectIdentifier(genderOidStr),
				new DERSet(new DERPrintableString("010-82961368"
						.getBytes("UTF-8"))));
		Attribute mobileTelephoneNumberAttribute = new Attribute(
				new DERObjectIdentifier(genderOidStr),
				new DERSet(new DERPrintableString("13843838438"
						.getBytes("UTF-8"))));

		attributes.add(genderAttribute);
		attributes.add(dateOfBirthAttribute);
		attributes.add(streetAddressAttribute);
		attributes.add(telephoneNumberAttribute);
		attributes.add(mobileTelephoneNumberAttribute);

		// 构建主题目录属性
		SubjectDirectoryAttributes sda = new SubjectDirectoryAttributes(
				attributes);

		extGen.addExtension(X509Extensions.SubjectDirectoryAttributes, false,
				sda);

		/**
		 * 名称限制 : 只在ca中出现,并不是出现在用户证书中,名称限制同时对Subject和SubjeectAltertiveName
		 * 起作用。可以对多种命名进行限制如Email、DNS、X509 DN 等
		 * 如果发现用户证书中的命名(Subject和SubjeectAltertiveName)与CA证书中的Name
		 * Constraints违背,就直接认为该证书无效。必须满足Name Constraints 中的多个不同类型命名的限制
		 * NameConstraints ::= SEQUENCE { permittedSubtrees [0] GeneralSubtrees
		 * OPTIONAL, excludedSubtrees [1] GeneralSubtrees OPTIONAL }
		 * GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree
		 */
		Vector<GeneralSubtree> permitted = new Vector<GeneralSubtree>(); // 允许名称列表
		Vector<GeneralSubtree> excluded = new Vector<GeneralSubtree>(); // 限制名称列表

		// 添加允许名称
		GeneralName permitteedNcGn = new GeneralName(GeneralName.directoryName,
				map.get(GeneralName.directoryName));
		GeneralSubtree permittedGsNcGn = new GeneralSubtree(permitteedNcGn,
				BigInteger.ONE, BigInteger.TEN);
		permitted.add(permittedGsNcGn);
		// 添加限制名称
		GeneralName excludedNcGn = new GeneralName(GeneralName.directoryName,
				map.get(GeneralName.directoryName));
		GeneralSubtree excludedGsNcGn = new GeneralSubtree(excludedNcGn,
				BigInteger.ONE, BigInteger.TEN);
		excluded.add(excludedGsNcGn);

		NameConstraints nc = new NameConstraints(permitted, excluded);

		extGen.addExtension(X509Extensions.NameConstraints, false, nc);

		/**
		 * 机构信息访问 id-pe-authorityInfoAccess OBJECT IDENTIFIER ::= { id-pe 1 }
		 * AuthorityInfoAccessSyntax ::= SEQUENCE SIZE (1..MAX) OF
		 * AccessDescription AccessDescription ::= SEQUENCE { accessMethod
		 * OBJECT IDENTIFIER, accessLocation GeneralName } id-ad OBJECT
		 * IDENTIFIER ::= { id-pkix 48 } id-ad-caIssuers OBJECT IDENTIFIER ::= {
		 * id-ad 2 } id-ad-ocsp OBJECT IDENTIFIER ::= { id-ad 1 }
		 */
		ASN1EncodableVector authorityInnfoAccess = new ASN1EncodableVector();

		DERObjectIdentifier id_ad_caIssuers = AccessDescription.id_ad_caIssuers;
		DERObjectIdentifier id_ad_ocsp = AccessDescription.id_ad_ocsp;
		DERObjectIdentifier id_ad_caRepository = new DERObjectIdentifier(
				"1.3.6.1.5.5.7.48.5");

		AccessDescription caIssuers = new AccessDescription(id_ad_caIssuers,
				new GeneralName(GeneralName.uniformResourceIdentifier,
						"http://certService/caIssuers"));
		AccessDescription ocsp = new AccessDescription(id_ad_caIssuers,
				new GeneralName(GeneralName.uniformResourceIdentifier,
						"http://certService/ocsp"));
		AccessDescription caRepository = new AccessDescription(id_ad_caIssuers,
				new GeneralName(GeneralName.uniformResourceIdentifier,
						"http://certService/caRepository"));

		authorityInnfoAccess.add(caIssuers);
		authorityInnfoAccess.add(ocsp);
		authorityInnfoAccess.add(caRepository);

		extGen.addExtension(X509Extensions.AuthorityInfoAccess, false,
				new DERSequence(authorityInnfoAccess));
		/**
	     * 
	     */

		/**
		 * 证书策略
		 * 
		 * <pre>
		 * 
		 * certificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation
		 * 
		 * PolicyInformation ::= SEQUENCE {
		 *   policyIdentifier   CertPolicyId,
		 *   policyQualifiers   SEQUENCE SIZE (1..MAX) OF
		 *                           PolicyQualifierInfo OPTIONAL }
		 * 
		 * CertPolicyId ::= OBJECT IDENTIFIER
		 * 
		 * PolicyQualifierInfo ::= SEQUENCE {
		 *   policyQualifierId  PolicyQualifierId,
		 *   qualifier          ANY DEFINED BY policyQualifierId }
		 * 
		 * PolicyQualifierId ::=
		 *   OBJECT IDENTIFIER (id-qt-cps | id-qt-unotice)
		 * </pre>
		 * 
		 * @deprecated use an ASN1Sequence of PolicyInformation
		 */
		PolicyInformation policyInfo1 = new PolicyInformation(
				new DERObjectIdentifier("1.1.1.2.3.1"));
		PolicyInformation policyInfo2 = new PolicyInformation(
				new DERObjectIdentifier("1.1.1.2.3.2"));
		PolicyInformation policyInfo3 = new PolicyInformation(
				new DERObjectIdentifier("1.1.1.2.3.3"));

		ASN1EncodableVector certificatePolicies = new ASN1EncodableVector();
		certificatePolicies.add(policyInfo1);
		certificatePolicies.add(policyInfo2);
		certificatePolicies.add(policyInfo3);

		extGen.addExtension(X509Extensions.CertificatePolicies, true,
				new DERSequence(certificatePolicies));

		return extGen.generate();
	}
    /**
     * 产生密钥对
     * @param alg  签名算法
     * @return  密钥对
     * @throws Exception
     */
	public static KeyPair genKeyPair(String alg) throws Exception {
		KeyPairGenerator genKeyPair = KeyPairGenerator.getInstance(alg);
		genKeyPair.initialize(2048);
		return genKeyPair.genKeyPair();
	}
	/**
	 * 签名 
	 * @param alg  签名算法 
	 * @param planText 签名原文
	 * @param priKey   签名私钥
	 * @return   签名信息  byte[]
	 * @throws Exception
	 */
	public static byte[] sign(String alg, byte[] planText, PrivateKey priKey)
			throws Exception {
		if (alg == null)
			return null;
		if ("RSA".equals(alg))
			alg = "SHA1withRSA";
		else
			throw new Exception("不支持的算法。");

		Signature sign = Signature.getInstance(alg);
		sign.initSign(priKey);
		sign.update(planText);
		return sign.sign();
	}

}
分享到:
评论

相关推荐

    Java基于BC生成X509v3证书,以及部分扩展Extension的使用

    Java基于BC生成X509v3证书,以及部分扩展Extension的使用,如:BasicConstraints、CRLDIstPoint、CertificatePolicies、PolicyMappings、KeyUsage、ExtendedKeyUsage、SubjectAlternativeName、AuthorityInfoAccess...

    java-sm2 - 副本.zip

    实现了SM2中如下5部分1.生成密钥对2.签名与验签3....利用BC的X509v3CertificateBuilder组装X509国密证书生成证书,,,杂凑算法采用SM3 密钥派生算法参考国密办文档中的KDF实现具体可查看resouces中三个文档

    PKCS7 数字信封项目源码

    3. **公钥加密**:将生成的对称密钥使用接收方的公开证书(包含公钥)进行加密,形成“内层”加密。 4. **组合**:将公钥加密后的对称密钥(即数字信封)与对称加密后的数据结合,形成完整的PKCS7消息。 5. **传输...

    azkaban安装

    组装文件 由于编译得到的 tar 包并不完整,还需要添加一些必要的文件。 - **Web 端** - 添加 `conf`, `azkaban`, `plugins` 和 `extlib` 目录。 - 其中 `azkaban` 目录可以直接从 web 工程复制而来。 - `conf`...

    基于A*算法的往返式全覆盖路径规划改进及其Matlab实现

    内容概要:本文详细介绍了如何利用A*算法改进传统的往返式路径规划,解决扫地机器人在复杂环境中容易卡住的问题。首先构建了一个可视化的栅格地图用于模拟环境,然后引入了优先级运动规则,使机器人能够有规律地进行往返清扫。当遇到死角时,通过A*算法计算最佳逃生路径,确保机器人能够顺利脱困并继续完成清扫任务。实验结果显示,改进后的算法显著提高了清洁覆盖率,降低了路径重复率。此外,还讨论了一些潜在的优化方向,如动态调整启发函数权重、断点续传以及能耗模型等。 适合人群:对路径规划算法感兴趣的科研人员、自动化专业学生、扫地机器人开发者。 使用场景及目标:适用于需要高覆盖率和低重复率的室内清洁任务,旨在提高扫地机器人的工作效率和智能化水平。 其他说明:文中提供了详细的Matlab代码实现,并附带了仿真测试结果,有助于读者理解和复现该算法。

    爬取喜马拉雅听书(1).py

    爬取喜马拉雅听书(1)

    安卓向上传递数据学习笔记总结

    安卓向上传递数据学习笔记总结

    tigervnc-selinux-1.11.0-9.el8.x64-86.rpm.tar.gz

    1、文件说明: Centos8操作系统tigervnc-selinux-1.11.0-9.el8.rpm以及相关依赖,全打包为一个tar.gz压缩包 2、安装指令: #Step1、解压 tar -zxvf tigervnc-selinux-1.11.0-9.el8.tar.gz #Step2、进入解压后的目录,执行安装 sudo rpm -ivh *.rpm

    户外储能电源双向逆变器板生产资料及技术规格详解

    内容概要:本文详细介绍了户外储能电源双向逆变器板的技术资料及其特点。涵盖原理文件、PCB文件、源代码、电感与变压器规格参数等,适用于2KW(最大3KW)的户外储能电源。文中强调了双向软开关DC-DC设计、两颗M0+ 32位MCU的分工、SPWM调制方式、H桥IGBT的应用、详细的电气参数和技术特性。此外,还包括了SPWM信号生成代码示例、硬件设计细节、生产注意事项等。 适合人群:从事户外储能电源开发的技术人员、电子工程师、产品经理等。 使用场景及目标:帮助开发者快速掌握双向逆变器板的设计和生产要点,缩短产品研发周期,提高产品质量和可靠性。具体应用场景包括但不限于户外应急电源、便携式储能设备等。 其他说明:本文提供了丰富的技术细节和实践经验,如双向软开关DC-DC设计、SPWM调制、IGBT驱动、EMC整改记录等,有助于解决实际开发中的难题。同时,附带的实际案例展示了该方案的成功应用,进一步证明了其可行性和优越性。

    电能质量分析:间谐波分析.zip

    电子仿真教程,从基础到精通,每个压缩包15篇教程,每篇教程5000字以上。

    【计算机科学领域】美国计算机学会(ACM):组织架构、使命愿景、核心价值及活动项目介绍

    内容概要:美国计算机学会(ACM)是一个成立于1947年的国际性计算机专业组织,致力于推动计算机科学的发展,提供教育、资源和专业发展机会。ACM的使命是促进计算机科学和信息技术领域的进步,愿景是成为全球计算机专业人士的首选组织。其核心价值包括卓越、诚信、包容性、合作和创新。ACM定期举办学术会议,如SIGGRAPH和图灵奖颁奖典礼,出版高质量的学术期刊和会议论文集,涵盖人工智能、软件工程、网络安全等领域。此外,ACM还提供在线课程、研讨会、认证项目等教育资源,以及职业规划、网络机会和领导力培训等职业发展服务。ACM图灵奖被誉为“计算机界的诺贝尔奖”,每年颁发给对计算机科学和技术做出重大贡献的个人。; 适合人群:计算机科学领域的专业人士、教育工作者、工程师和学生。; 使用场景及目标:①了解计算机科学领域的最新研究成果和发展趋势;②获取高质量的教育资源和职业发展机会;③参与计算机科学领域的学术交流和合作。; 其他说明:ACM作为一个全球性的组织,在教育、研究和行业实践中发挥着重要作用,推动了技术创新和社会进步。

    最新版logstash-8.17.4-windows-x86-64.zip

    logstash-8.17.4-windows-x86_64.zip

    一个基于Springboot使用Aspect实现一个切面,以记录日志为例

    springboot 一个基于Springboot使用Aspect实现一个切面,以记录日志为例

    音箱底部折边设备sw22可编辑_三维3D设计图纸_包括零件图_机械3D图可修改打包下载_三维3D设计图纸_包括零件图_机械3D图可修改打包下载.zip

    音箱底部折边设备sw22可编辑_三维3D设计图纸_包括零件图_机械3D图可修改打包下载_三维3D设计图纸_包括零件图_机械3D图可修改打包下载.zip

    基于Python Django MySQL的个性化图书推荐系统:协同过滤算法及远程部署实现

    内容概要:本文详细介绍了如何使用Python、Django和MySQL构建一个完整的个性化图书推荐系统。系统从前端界面设计、后端逻辑实现到数据库设计,涵盖了用户管理、图书管理、评分系统等功能模块。重点讲解了基于用户和项目的协同过滤算法实现,以及在用户评分数据不足时的标签推荐备份方案。此外,还包括了系统部署、测试和优化的具体步骤,如云服务器部署、性能测试、数据库优化等。 适合人群:具备一定Python和Web开发基础的研发人员,尤其是对推荐系统感兴趣的技术爱好者。 使用场景及目标:适用于希望深入了解图书推荐系统的工作原理和实现细节的技术人员。目标是帮助读者掌握从零开始搭建一个完整的个性化推荐系统的方法,包括前后端开发、算法实现和系统部署。 其他说明:文中提供了大量代码示例和实战经验,如数据库设计、爬虫实现、权限管理等,有助于读者更好地理解和应用相关技术。

    Ai和python学习资料

    Ai和python学习资料

    文本摘要.py

    文本摘要

    冲击试验机sw22_三维3D设计图纸_包括零件图_机械3D图可修改打包下载_三维3D设计图纸_包括零件图_机械3D图可修改打包下载.zip

    冲击试验机sw22_三维3D设计图纸_包括零件图_机械3D图可修改打包下载_三维3D设计图纸_包括零件图_机械3D图可修改打包下载.zip

    Java开发MybatisPlus框架详解:增强Mybatis功能实现高效CRUD操作与代码生成

    内容概要:本文详细介绍了MyBatis Plus(MP),它是MyBatis的增强工具,旨在简化CRUD操作、提高开发效率。其主要功能包括内置分页插件、简化CRUD操作以及代码生成器。使用时只需引入相应依赖,自定义Mapper接口继承BaseMapper泛型接口,并通过实体类反射获取数据库表信息。文章还介绍了常用注解如@TableName、@TableId、@TableField、@TableLogic和@Version,配置项如全局配置、类型别名和Mapper文件路径,以及核心功能如批量插入、分页查询、条件构造器(Wrapper)等。此外,扩展功能涵盖逻辑删除、枚举处理器和JSON处理器,插件功能则包括分页插件的配置和使用。 适合人群:具备一定Java开发经验,尤其是熟悉MyBatis框架的开发者,特别是那些希望提高开发效率、减少重复代码的工作1-3年研发人员。 使用场景及目标:①简化数据库操作,提高开发效率;②快速生成代码,减少手动编写SQL语句的工作量;③实现分页查询、逻辑删除、枚举和JSON字段处理等高级功能,提升应用的灵活性和可维护性。 其他说明:本文不仅提供了MyBatis Plus的功能介绍和使用方法,还深入探讨了条件构造器(Wrapper)的使用技巧,帮助开发者更好地理解和掌握这一强大的工具。在实际开发中,合理利用这些功能可以显著提高开发效率和代码质量。建议在学习过程中结合具体项目实践,逐步掌握各个功能的应用场景和最佳实践。

    电路仿真:射频电路仿真.zip

    电子仿真教程,从基础到精通,每个压缩包15篇教程,每篇教程5000字以上。

Global site tag (gtag.js) - Google Analytics