use of org.xipki.security.KeypairGenerator in project xipki by xipki.
the class GrandCertTemplateBuilder method create.
GrantedCertTemplate create(IdentifiedCertprofile certprofile, CertTemplateData certTemplate, RequestorInfo requestor, List<KeypairGenerator> keypairGenerators, boolean update) throws OperationException {
if (caInfo.getRevocationInfo() != null) {
throw new OperationException(NOT_PERMITTED, "CA is revoked");
}
if (certprofile == null) {
throw new OperationException(UNKNOWN_CERT_PROFILE, "unknown cert profile " + certTemplate.getCertprofileName());
}
ConcurrentContentSigner signer = caInfo.getSigner(certprofile.getSignatureAlgorithms());
if (signer == null) {
throw new OperationException(SYSTEM_FAILURE, "CA does not support any signature algorithm restricted by the cert profile");
}
final NameId certprofileIdent = certprofile.getIdent();
if (certprofile.getVersion() != Certprofile.X509CertVersion.v3) {
throw new OperationException(SYSTEM_FAILURE, "unknown cert version " + certprofile.getVersion());
}
if (certprofile.isOnlyForRa()) {
if (requestor == null || !requestor.isRa()) {
throw new OperationException(NOT_PERMITTED, "profile " + certprofileIdent + " not applied to non-RA");
}
}
switch(certprofile.getCertLevel()) {
case RootCA:
throw new OperationException(NOT_PERMITTED, "CA is not allowed to generate Root CA certificate");
case SubCA:
Integer reqPathlen = certprofile.getPathLenBasicConstraint();
int caPathLen = caInfo.getPathLenConstraint();
boolean allowed = (reqPathlen == null && caPathLen == Integer.MAX_VALUE) || (reqPathlen != null && reqPathlen < caPathLen);
if (!allowed) {
throw new OperationException(NOT_PERMITTED, "invalid BasicConstraint.pathLenConstraint");
}
break;
default:
}
X500Name requestedSubject = CaUtil.removeEmptyRdns(certTemplate.getSubject());
if (!certprofile.isSerialNumberInReqPermitted()) {
RDN[] rdns = requestedSubject.getRDNs(ObjectIdentifiers.DN.SN);
if (rdns != null && rdns.length > 0) {
throw new OperationException(BAD_CERT_TEMPLATE, "subjectDN SerialNumber in request is not permitted");
}
}
Date reqNotBefore = certTemplate.getNotBefore();
Date grantedNotBefore = certprofile.getNotBefore(reqNotBefore);
// notBefore in the past is not permitted (due to the fact that some clients may not have
// accurate time, we allow max. 5 minutes in the past)
long currentMillis = System.currentTimeMillis();
if (currentMillis - grantedNotBefore.getTime() > MS_PER_10MINUTES) {
grantedNotBefore = new Date(currentMillis - MS_PER_10MINUTES);
}
long time = caInfo.getNoNewCertificateAfter();
if (grantedNotBefore.getTime() > time) {
throw new OperationException(NOT_PERMITTED, "CA is not permitted to issue certificate after " + new Date(time));
}
if (grantedNotBefore.before(caInfo.getNotBefore())) {
// notBefore may not be before CA's notBefore
grantedNotBefore = caInfo.getNotBefore();
}
PrivateKeyInfo privateKey = null;
SubjectPublicKeyInfo grantedPublicKeyInfo = certTemplate.getPublicKeyInfo();
if (grantedPublicKeyInfo != null) {
try {
grantedPublicKeyInfo = X509Util.toRfc3279Style(certTemplate.getPublicKeyInfo());
} catch (InvalidKeySpecException ex) {
LogUtil.warn(LOG, ex, "invalid SubjectPublicKeyInfo");
throw new OperationException(BAD_CERT_TEMPLATE, "invalid SubjectPublicKeyInfo");
}
// CHECK weak public key, like RSA key (ROCA)
if (grantedPublicKeyInfo.getAlgorithm().getAlgorithm().equals(PKCSObjectIdentifiers.rsaEncryption)) {
try {
ASN1Sequence seq = ASN1Sequence.getInstance(grantedPublicKeyInfo.getPublicKeyData().getOctets());
if (seq.size() != 2) {
throw new OperationException(BAD_CERT_TEMPLATE, "invalid format of RSA public key");
}
BigInteger modulus = ASN1Integer.getInstance(seq.getObjectAt(0)).getPositiveValue();
if (RSABrokenKey.isAffected(modulus)) {
throw new OperationException(BAD_CERT_TEMPLATE, "RSA public key is too weak");
}
} catch (IllegalArgumentException ex) {
throw new OperationException(BAD_CERT_TEMPLATE, "invalid format of RSA public key");
}
}
} else if (certTemplate.isCaGenerateKeypair()) {
KeypairGenControl kg = certprofile.getKeypairGenControl();
ASN1ObjectIdentifier keyAlgOid;
String keyspec;
if (kg == null || kg instanceof KeypairGenControl.ForbiddenKeypairGenControl) {
throw new OperationException(BAD_CERT_TEMPLATE, "no public key is specified");
}
if (kg instanceof KeypairGenControl.InheritCAKeypairGenControl) {
keyspec = keyspecByImplicitCA;
keyAlgOid = keyAlgOidByImplicitCA;
} else {
keyspec = kg.getKeyspec();
keyAlgOid = kg.getKeyAlgorithmOid();
}
KeypairGenerator keypairGenerator = null;
if (keypairGenerators != null) {
for (KeypairGenerator m : keypairGenerators) {
if (m.supports(keyspec)) {
keypairGenerator = m;
break;
}
}
}
if (keypairGenerator == null) {
throw new OperationException(SYSTEM_FAILURE, "found no keypair generator for keyspec " + keyspec);
}
String name = keypairGenerator.getName();
try {
privateKey = keypairGenerator.generateKeypair(keyspec);
LOG.info("generated keypair {} with generator {}", keyspec, name);
} catch (XiSecurityException ex) {
String msg = "error generating keypair " + keyspec + " using generator " + name;
LogUtil.error(LOG, ex, msg);
throw new OperationException(SYSTEM_FAILURE, msg);
}
// adapt the algorithm identifier in private key and public key
if (!privateKey.getPrivateKeyAlgorithm().getAlgorithm().equals(keyAlgOid)) {
ASN1BitString asn1PublicKeyData = privateKey.getPublicKeyData();
try {
privateKey = new PrivateKeyInfo(new AlgorithmIdentifier(keyAlgOid, privateKey.getPrivateKeyAlgorithm().getParameters()), privateKey.getPrivateKey().toASN1Primitive(), privateKey.getAttributes(), asn1PublicKeyData == null ? null : asn1PublicKeyData.getOctets());
} catch (IOException ex) {
throw new OperationException(SYSTEM_FAILURE, ex);
}
}
// construct SubjectPublicKeyInfo
String keyType = keyspec.split("/")[0].toUpperCase(Locale.ROOT);
byte[] publicKeyData;
switch(keyType) {
case "RSA":
{
RSAPrivateKey sk = RSAPrivateKey.getInstance(privateKey.getPrivateKey().getOctets());
try {
publicKeyData = new RSAPublicKey(sk.getModulus(), sk.getPublicExponent()).getEncoded();
} catch (IOException ex) {
throw new OperationException(SYSTEM_FAILURE, ex);
}
break;
}
case "EC":
{
ECPrivateKey sk = ECPrivateKey.getInstance(privateKey.getPrivateKey().getOctets());
publicKeyData = sk.getPublicKey().getBytes();
break;
}
case "DSA":
case "ED25519":
case "ED448":
case "X25519":
case "X448":
{
publicKeyData = privateKey.getPublicKeyData().getBytes();
break;
}
default:
throw new IllegalStateException("unknown key type " + keyType);
}
grantedPublicKeyInfo = new SubjectPublicKeyInfo(privateKey.getPrivateKeyAlgorithm(), publicKeyData);
try {
grantedPublicKeyInfo = X509Util.toRfc3279Style(grantedPublicKeyInfo);
} catch (InvalidKeySpecException ex) {
throw new OperationException(SYSTEM_FAILURE, ex);
}
} else {
// show not reach here
throw new OperationException(BAD_CERT_TEMPLATE, "no public key is specified");
}
// public key
try {
grantedPublicKeyInfo = certprofile.checkPublicKey(grantedPublicKeyInfo);
} catch (CertprofileException ex) {
throw new OperationException(SYSTEM_FAILURE, "exception in cert profile " + certprofileIdent);
} catch (BadCertTemplateException ex) {
throw new OperationException(BAD_CERT_TEMPLATE, ex);
}
// subject
Certprofile.SubjectInfo subjectInfo;
try {
subjectInfo = certprofile.getSubject(requestedSubject, grantedPublicKeyInfo);
} catch (CertprofileException ex) {
throw new OperationException(SYSTEM_FAILURE, "exception in cert profile " + certprofileIdent);
} catch (BadCertTemplateException ex) {
throw new OperationException(BAD_CERT_TEMPLATE, ex);
}
X500Name grantedSubject = subjectInfo.getGrantedSubject();
// make sure that empty subject is not permitted
ASN1ObjectIdentifier[] attrTypes = grantedSubject.getAttributeTypes();
if (attrTypes == null || attrTypes.length == 0) {
throw new OperationException(BAD_CERT_TEMPLATE, "empty subject is not permitted");
}
// make sure that the grantedSubject does not equal the CA's subject
if (X509Util.canonicalizName(grantedSubject).equals(caInfo.getPublicCaInfo().getC14nSubject())) {
throw new OperationException(ALREADY_ISSUED, "certificate with the same subject as CA is not allowed");
}
if (update) {
CertStore.CertStatus certStatus = certstore.getCertStatusForSubject(caInfo.getIdent(), grantedSubject);
if (certStatus == CertStore.CertStatus.REVOKED) {
throw new OperationException(CERT_REVOKED);
} else if (certStatus == CertStore.CertStatus.UNKNOWN) {
throw new OperationException(UNKNOWN_CERT);
}
}
// end if(update)
StringBuilder msgBuilder = new StringBuilder();
if (subjectInfo.getWarning() != null) {
msgBuilder.append(", ").append(subjectInfo.getWarning());
}
Validity validity = certprofile.getValidity();
if (validity == null) {
validity = caInfo.getMaxValidity();
} else if (validity.compareTo(caInfo.getMaxValidity()) > 0) {
validity = caInfo.getMaxValidity();
}
Date maxNotAfter = validity.add(grantedNotBefore);
// maxNotAfter not after 99991231-235959
if (maxNotAfter.getTime() > MAX_CERT_TIME_MS) {
maxNotAfter = MAX_CERT_TIME;
}
Date grantedNotAfter = certTemplate.getNotAfter();
if (grantedNotAfter != null) {
if (grantedNotAfter.after(maxNotAfter)) {
grantedNotAfter = maxNotAfter;
msgBuilder.append(", notAfter modified");
}
} else {
grantedNotAfter = maxNotAfter;
}
if (grantedNotAfter.after(caInfo.getNotAfter())) {
ValidityMode caMode = caInfo.getValidityMode();
NotAfterMode profileMode = certprofile.getNotAfterMode();
if (profileMode == null) {
profileMode = NotAfterMode.BY_CA;
}
if (profileMode == NotAfterMode.STRICT) {
throw new OperationException(NOT_PERMITTED, "notAfter outside of CA's validity is not permitted by the CertProfile");
}
if (caMode == ValidityMode.STRICT) {
throw new OperationException(NOT_PERMITTED, "notAfter outside of CA's validity is not permitted by the CA");
}
if (caMode == ValidityMode.CUTOFF) {
grantedNotAfter = caInfo.getNotAfter();
} else if (caMode == ValidityMode.LAX) {
if (profileMode == NotAfterMode.CUTOFF) {
grantedNotAfter = caInfo.getNotAfter();
}
} else {
throw new IllegalStateException("should not reach here, CA ValidityMode " + caMode + " CertProfile NotAfterMode " + profileMode);
}
// end if (mode)
}
// end if (notAfter)
String warning = null;
if (msgBuilder.length() > 2) {
warning = msgBuilder.substring(2);
}
GrantedCertTemplate gct = new GrantedCertTemplate(certTemplate.getExtensions(), certprofile, grantedNotBefore, grantedNotAfter, requestedSubject, grantedPublicKeyInfo, privateKey, signer, warning);
gct.setGrantedSubject(grantedSubject);
return gct;
}
Aggregations