use of org.xipki.ca.api.profile.CertprofileException in project xipki by xipki.
the class X509SelfSignedCertBuilder method generateCertificate.
// method generateSelfSigned
private static X509Certificate generateCertificate(ConcurrentContentSigner signer, IdentifiedX509Certprofile certprofile, CertificationRequest csr, BigInteger serialNumber, SubjectPublicKeyInfo publicKeyInfo, List<String> caCertUris, List<String> ocspUris, List<String> crlUris, List<String> deltaCrlUris, ConfPairs extraControl) throws OperationException {
SubjectPublicKeyInfo tmpPublicKeyInfo;
try {
tmpPublicKeyInfo = X509Util.toRfc3279Style(publicKeyInfo);
} catch (InvalidKeySpecException ex) {
LOG.warn("SecurityUtil.toRfc3279Style", ex);
throw new OperationException(ErrorCode.BAD_CERT_TEMPLATE, ex);
}
try {
certprofile.checkPublicKey(tmpPublicKeyInfo);
} catch (BadCertTemplateException ex) {
LOG.warn("certprofile.checkPublicKey", ex);
throw new OperationException(ErrorCode.BAD_CERT_TEMPLATE, ex);
}
X500Name requestedSubject = csr.getCertificationRequestInfo().getSubject();
SubjectInfo subjectInfo;
// subject
try {
subjectInfo = certprofile.getSubject(requestedSubject);
} catch (CertprofileException ex) {
throw new OperationException(ErrorCode.SYSTEM_FAILURE, "exception in cert profile " + certprofile.getIdent());
} catch (BadCertTemplateException ex) {
LOG.warn("certprofile.getSubject", ex);
throw new OperationException(ErrorCode.BAD_CERT_TEMPLATE, ex);
}
Date notBefore = certprofile.getNotBefore(null);
if (notBefore == null) {
notBefore = new Date();
}
CertValidity validity = certprofile.getValidity();
if (validity == null) {
throw new OperationException(ErrorCode.BAD_CERT_TEMPLATE, "no validity specified in the profile " + certprofile.getIdent());
}
Date notAfter = validity.add(notBefore);
X500Name grantedSubject = subjectInfo.getGrantedSubject();
X509v3CertificateBuilder certBuilder = new X509v3CertificateBuilder(grantedSubject, serialNumber, notBefore, notAfter, grantedSubject, tmpPublicKeyInfo);
PublicCaInfo publicCaInfo = new PublicCaInfo(grantedSubject, serialNumber, null, null, caCertUris, ocspUris, crlUris, deltaCrlUris, extraControl);
Extensions extensions = null;
ASN1Set attrs = csr.getCertificationRequestInfo().getAttributes();
for (int i = 0; i < attrs.size(); i++) {
Attribute attr = Attribute.getInstance(attrs.getObjectAt(i));
if (PKCSObjectIdentifiers.pkcs_9_at_extensionRequest.equals(attr.getAttrType())) {
extensions = Extensions.getInstance(attr.getAttributeValues()[0]);
}
}
try {
addExtensions(certBuilder, certprofile, requestedSubject, grantedSubject, extensions, tmpPublicKeyInfo, publicCaInfo, notBefore, notAfter);
ConcurrentBagEntrySigner signer0 = signer.borrowSigner();
X509CertificateHolder certHolder;
try {
certHolder = certBuilder.build(signer0.value());
} finally {
signer.requiteSigner(signer0);
}
Certificate bcCert = certHolder.toASN1Structure();
return X509Util.parseCert(bcCert.getEncoded());
} catch (BadCertTemplateException ex) {
throw new OperationException(ErrorCode.BAD_CERT_TEMPLATE, ex);
} catch (NoIdleSignerException | CertificateException | IOException | CertprofileException ex) {
throw new OperationException(ErrorCode.SYSTEM_FAILURE, ex);
}
}
use of org.xipki.ca.api.profile.CertprofileException in project xipki by xipki.
the class X509Ca method createGrantedCertTemplate.
private GrantedCertTemplate createGrantedCertTemplate(CertTemplateData certTemplate, RequestorInfo requestor, boolean keyUpdate) throws OperationException {
ParamUtil.requireNonNull("certTemplate", certTemplate);
if (caInfo.getRevocationInfo() != null) {
throw new OperationException(ErrorCode.NOT_PERMITTED, "CA is revoked");
}
IdentifiedX509Certprofile certprofile = getX509Certprofile(certTemplate.getCertprofileName());
if (certprofile == null) {
throw new OperationException(ErrorCode.UNKNOWN_CERT_PROFILE, "unknown cert profile " + certTemplate.getCertprofileName());
}
ConcurrentContentSigner signer = caInfo.getSigner(certprofile.getSignatureAlgorithms());
if (signer == null) {
throw new OperationException(ErrorCode.SYSTEM_FAILURE, "CA does not support any signature algorithm restricted by the cert profile");
}
final NameId certprofileIdent = certprofile.getIdent();
if (certprofile.getVersion() != X509CertVersion.v3) {
throw new OperationException(ErrorCode.SYSTEM_FAILURE, "unknown cert version " + certprofile.getVersion());
}
if (certprofile.isOnlyForRa()) {
if (requestor == null || !requestor.isRa()) {
throw new OperationException(ErrorCode.NOT_PERMITTED, "profile " + certprofileIdent + " not applied to non-RA");
}
}
X500Name requestedSubject = removeEmptyRdns(certTemplate.getSubject());
if (!certprofile.isSerialNumberInReqPermitted()) {
RDN[] rdns = requestedSubject.getRDNs(ObjectIdentifiers.DN_SN);
if (rdns != null && rdns.length > 0) {
throw new OperationException(ErrorCode.BAD_CERT_TEMPLATE, "subjectDN SerialNumber in request is not permitted");
}
}
Date now = new Date();
Date reqNotBefore;
if (certTemplate.getNotBefore() != null && certTemplate.getNotBefore().after(now)) {
reqNotBefore = certTemplate.getNotBefore();
} else {
reqNotBefore = now;
}
Date grantedNotBefore = certprofile.getNotBefore(reqNotBefore);
// notBefore in the past is not permitted
if (grantedNotBefore.before(now)) {
grantedNotBefore = now;
}
if (certprofile.hasMidnightNotBefore()) {
grantedNotBefore = setToMidnight(grantedNotBefore, certprofile.getTimezone());
}
if (grantedNotBefore.before(caInfo.getNotBefore())) {
grantedNotBefore = caInfo.getNotBefore();
if (certprofile.hasMidnightNotBefore()) {
grantedNotBefore = setToMidnight(grantedNotBefore, certprofile.getTimezone());
}
}
long time = caInfo.getNoNewCertificateAfter();
if (grantedNotBefore.getTime() > time) {
throw new OperationException(ErrorCode.NOT_PERMITTED, "CA is not permitted to issue certifate after " + new Date(time));
}
SubjectPublicKeyInfo grantedPublicKeyInfo;
try {
grantedPublicKeyInfo = X509Util.toRfc3279Style(certTemplate.getPublicKeyInfo());
} catch (InvalidKeySpecException ex) {
LogUtil.warn(LOG, ex, "invalid SubjectPublicKeyInfo");
throw new OperationException(ErrorCode.BAD_CERT_TEMPLATE, "invalid SubjectPublicKeyInfo");
}
// public key
try {
grantedPublicKeyInfo = certprofile.checkPublicKey(grantedPublicKeyInfo);
} catch (BadCertTemplateException ex) {
throw new OperationException(ErrorCode.BAD_CERT_TEMPLATE, ex);
}
// 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(ErrorCode.BAD_CERT_TEMPLATE, "invalid format of RSA public key");
}
BigInteger modulus = ASN1Integer.getInstance(seq.getObjectAt(0)).getPositiveValue();
if (RSABrokenKey.isAffected(modulus)) {
throw new OperationException(ErrorCode.BAD_CERT_TEMPLATE, "RSA public key is too weak");
}
} catch (IllegalArgumentException ex) {
throw new OperationException(ErrorCode.BAD_CERT_TEMPLATE, "invalid format of RSA public key");
}
}
Date gsmckFirstNotBefore = null;
if (certprofile.getspecialCertprofileBehavior() == SpecialX509CertprofileBehavior.gematik_gSMC_K) {
gsmckFirstNotBefore = grantedNotBefore;
RDN[] cnRdns = requestedSubject.getRDNs(ObjectIdentifiers.DN_CN);
if (cnRdns != null && cnRdns.length > 0) {
String requestedCn = X509Util.rdnValueToString(cnRdns[0].getFirst().getValue());
Long gsmckFirstNotBeforeInSecond = certstore.getNotBeforeOfFirstCertStartsWithCommonName(requestedCn, certprofileIdent);
if (gsmckFirstNotBeforeInSecond != null) {
gsmckFirstNotBefore = new Date(gsmckFirstNotBeforeInSecond * MS_PER_SECOND);
}
// append the commonName with '-' + yyyyMMdd
SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMdd");
dateF.setTimeZone(new SimpleTimeZone(0, "Z"));
String yyyyMMdd = dateF.format(gsmckFirstNotBefore);
String suffix = "-" + yyyyMMdd;
// append the -yyyyMMdd to the commonName
RDN[] rdns = requestedSubject.getRDNs();
for (int i = 0; i < rdns.length; i++) {
if (ObjectIdentifiers.DN_CN.equals(rdns[i].getFirst().getType())) {
rdns[i] = new RDN(ObjectIdentifiers.DN_CN, new DERUTF8String(requestedCn + suffix));
}
}
requestedSubject = new X500Name(rdns);
}
// end if
}
// end if
// subject
SubjectInfo subjectInfo;
try {
subjectInfo = certprofile.getSubject(requestedSubject);
} catch (CertprofileException ex) {
throw new OperationException(ErrorCode.SYSTEM_FAILURE, "exception in cert profile " + certprofileIdent);
} catch (BadCertTemplateException ex) {
throw new OperationException(ErrorCode.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(ErrorCode.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(ErrorCode.ALREADY_ISSUED, "certificate with the same subject as CA is not allowed");
}
boolean duplicateKeyPermitted = caInfo.isDuplicateKeyPermitted();
if (duplicateKeyPermitted && !certprofile.isDuplicateKeyPermitted()) {
duplicateKeyPermitted = false;
}
byte[] subjectPublicKeyData = grantedPublicKeyInfo.getPublicKeyData().getBytes();
long fpPublicKey = FpIdCalculator.hash(subjectPublicKeyData);
if (keyUpdate) {
CertStatus certStatus = certstore.getCertStatusForSubject(caIdent, grantedSubject);
if (certStatus == CertStatus.REVOKED) {
throw new OperationException(ErrorCode.CERT_REVOKED);
} else if (certStatus == CertStatus.UNKNOWN) {
throw new OperationException(ErrorCode.UNKNOWN_CERT);
}
} else {
if (!duplicateKeyPermitted) {
if (certstore.isCertForKeyIssued(caIdent, fpPublicKey)) {
throw new OperationException(ErrorCode.ALREADY_ISSUED, "certificate for the given public key already issued");
}
}
// duplicateSubject check will be processed later
}
// end if(keyUpdate)
StringBuilder msgBuilder = new StringBuilder();
if (subjectInfo.getWarning() != null) {
msgBuilder.append(", ").append(subjectInfo.getWarning());
}
CertValidity validity = certprofile.getValidity();
if (validity == null) {
validity = caInfo.getMaxValidity();
} else if (validity.compareTo(caInfo.getMaxValidity()) > 0) {
validity = caInfo.getMaxValidity();
}
Date maxNotAfter = validity.add(grantedNotBefore);
if (maxNotAfter.getTime() > MAX_CERT_TIME_MS) {
maxNotAfter = new Date(MAX_CERT_TIME_MS);
}
// CHECKSTYLE:SKIP
Date origMaxNotAfter = maxNotAfter;
if (certprofile.getspecialCertprofileBehavior() == SpecialX509CertprofileBehavior.gematik_gSMC_K) {
String str = certprofile.setParameter(SpecialX509CertprofileBehavior.PARAMETER_MAXLIFTIME);
long maxLifetimeInDays = Long.parseLong(str);
Date maxLifetime = new Date(gsmckFirstNotBefore.getTime() + maxLifetimeInDays * DAY_IN_MS - MS_PER_SECOND);
if (maxNotAfter.after(maxLifetime)) {
maxNotAfter = maxLifetime;
}
}
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 mode = caInfo.getValidityMode();
if (mode == ValidityMode.CUTOFF) {
grantedNotAfter = caInfo.getNotAfter();
} else if (mode == ValidityMode.STRICT) {
throw new OperationException(ErrorCode.NOT_PERMITTED, "notAfter outside of CA's validity is not permitted");
} else if (mode == ValidityMode.LAX) {
// permitted
} else {
throw new RuntimeException("should not reach here, unknown CA ValidityMode " + mode);
}
// end if (mode)
}
if (certprofile.hasMidnightNotBefore() && !maxNotAfter.equals(origMaxNotAfter)) {
Calendar cal = Calendar.getInstance(certprofile.getTimezone());
cal.setTime(new Date(grantedNotAfter.getTime() - DAY_IN_MS));
cal.set(Calendar.HOUR_OF_DAY, 23);
cal.set(Calendar.MINUTE, 59);
cal.set(Calendar.SECOND, 59);
cal.set(Calendar.MILLISECOND, 0);
grantedNotAfter = cal.getTime();
}
String warning = null;
if (msgBuilder.length() > 2) {
warning = msgBuilder.substring(2);
}
GrantedCertTemplate gct = new GrantedCertTemplate(certTemplate.getExtensions(), certprofile, grantedNotBefore, grantedNotAfter, requestedSubject, grantedPublicKeyInfo, fpPublicKey, subjectPublicKeyData, signer, warning);
gct.setGrantedSubject(grantedSubject);
return gct;
}
use of org.xipki.ca.api.profile.CertprofileException in project xipki by xipki.
the class QaSystemManagerImpl method init.
public void init() {
if (StringUtil.isBlank(confFile)) {
throw new IllegalStateException("confFile must not be null and empty");
}
LOG.info("initializing ...");
if (initialized.get()) {
LOG.info("already initialized, skipping ...");
return;
}
QAConfType qaConf;
try {
FileInputStream issuerConfStream = new FileInputStream(confFile);
qaConf = parseQaConf(issuerConfStream);
} catch (IOException | JAXBException | SAXException ex) {
final String message = "could not parse the QA configuration";
LogUtil.error(LOG, ex, message);
return;
}
if (qaConf.getX509Issuers() != null) {
List<X509IssuerType> x509IssuerTypes = qaConf.getX509Issuers().getX509Issuer();
for (X509IssuerType issuerType : x509IssuerTypes) {
byte[] certBytes;
try {
certBytes = readData(issuerType.getCert());
} catch (IOException ex) {
LogUtil.error(LOG, ex, "could not read the certificate bytes of issuer " + issuerType.getName());
continue;
}
String str = issuerType.getValidityMode();
boolean cutoffNotAfter;
if (StringUtil.isBlank(str) || "CUTOFF".equalsIgnoreCase(str)) {
cutoffNotAfter = true;
} else if ("LAX".equalsIgnoreCase(str)) {
cutoffNotAfter = false;
} else {
LOG.error("invalid validityMode {}", str);
return;
}
X509IssuerInfo issuerInfo;
try {
issuerInfo = new X509IssuerInfo(issuerType.getCaIssuerUrl(), issuerType.getOcspUrl(), issuerType.getCrlUrl(), issuerType.getDeltaCrlUrl(), certBytes, cutoffNotAfter);
} catch (CertificateException ex) {
LogUtil.error(LOG, ex, "could not parse certificate of issuer " + issuerType.getName());
continue;
}
x509IssuerInfoMap.put(issuerType.getName(), issuerInfo);
LOG.info("configured X509 issuer {}", issuerType.getName());
}
}
if (qaConf.getX509Certprofiles() != null) {
List<X509CertprofileType> certprofileTypes = qaConf.getX509Certprofiles().getX509Certprofile();
for (X509CertprofileType type : certprofileTypes) {
String name = type.getName();
try {
byte[] content = readData(type);
x509ProfileMap.put(name, new X509CertprofileQa(content));
LOG.info("configured X509 certificate profile {}", name);
} catch (IOException | CertprofileException ex) {
LogUtil.error(LOG, ex, "could not parse QA certificate profile " + name);
continue;
}
}
}
initialized.set(true);
LOG.info("initialized");
}
use of org.xipki.ca.api.profile.CertprofileException in project xipki by xipki.
the class IdentifiedX509Certprofile method getExtensions.
/**
* TODO.
* @param requestedSubject
* Subject requested subject. Must not be {@code null}.
* @param grantedSubject
* Granted subject. Must not be {@code null}.
* @param requestedExtensions
* Extensions requested by the requestor. Could be {@code null}.
* @param publicKeyInfo
* Subject public key. Must not be {@code null}.
* @param publicCaInfo
* CA information. Must not be {@code null}.
* @param crlSignerCert
* CRL signer certificate. Could be {@code null}.
* @param notBefore
* NotBefore. Must not be {@code null}.
* @param notAfter
* NotAfter. Must not be {@code null}.
* @param caInfo
* CA information.
* @return the extensions of the certificate to be issued.
*/
public ExtensionValues getExtensions(X500Name requestedSubject, X500Name grantedSubject, Extensions requestedExtensions, SubjectPublicKeyInfo publicKeyInfo, PublicCaInfo publicCaInfo, X509Certificate crlSignerCert, Date notBefore, Date notAfter) throws CertprofileException, BadCertTemplateException {
ParamUtil.requireNonNull("publicKeyInfo", publicKeyInfo);
ExtensionValues values = new ExtensionValues();
Map<ASN1ObjectIdentifier, ExtensionControl> controls = new HashMap<>(certprofile.getExtensionControls());
Set<ASN1ObjectIdentifier> neededExtTypes = new HashSet<>();
Set<ASN1ObjectIdentifier> wantedExtTypes = new HashSet<>();
if (requestedExtensions != null) {
Extension reqExtension = requestedExtensions.getExtension(ObjectIdentifiers.id_xipki_ext_cmpRequestExtensions);
if (reqExtension != null) {
ExtensionExistence ee = ExtensionExistence.getInstance(reqExtension.getParsedValue());
neededExtTypes.addAll(ee.getNeedExtensions());
wantedExtTypes.addAll(ee.getWantExtensions());
}
for (ASN1ObjectIdentifier oid : neededExtTypes) {
if (wantedExtTypes.contains(oid)) {
wantedExtTypes.remove(oid);
}
if (!controls.containsKey(oid)) {
throw new BadCertTemplateException("could not add needed extension " + oid.getId());
}
}
}
// SubjectKeyIdentifier
ASN1ObjectIdentifier extType = Extension.subjectKeyIdentifier;
ExtensionControl extControl = controls.remove(extType);
if (extControl != null && addMe(extType, extControl, neededExtTypes, wantedExtTypes)) {
byte[] encodedSpki = publicKeyInfo.getPublicKeyData().getBytes();
byte[] skiValue = HashAlgo.SHA1.hash(encodedSpki);
SubjectKeyIdentifier value = new SubjectKeyIdentifier(skiValue);
addExtension(values, extType, value, extControl, neededExtTypes, wantedExtTypes);
}
// Authority key identifier
extType = Extension.authorityKeyIdentifier;
extControl = controls.remove(extType);
if (extControl != null && addMe(extType, extControl, neededExtTypes, wantedExtTypes)) {
byte[] ikiValue = publicCaInfo.getSubjectKeyIdentifer();
AuthorityKeyIdentifier value = null;
if (ikiValue != null) {
if (certprofile.includesIssuerAndSerialInAki()) {
GeneralNames x509CaSubject = new GeneralNames(new GeneralName(publicCaInfo.getX500Subject()));
value = new AuthorityKeyIdentifier(ikiValue, x509CaSubject, publicCaInfo.getSerialNumber());
} else {
value = new AuthorityKeyIdentifier(ikiValue);
}
}
addExtension(values, extType, value, extControl, neededExtTypes, wantedExtTypes);
}
// IssuerAltName
extType = Extension.issuerAlternativeName;
extControl = controls.remove(extType);
if (extControl != null && addMe(extType, extControl, neededExtTypes, wantedExtTypes)) {
GeneralNames value = publicCaInfo.getSubjectAltName();
addExtension(values, extType, value, extControl, neededExtTypes, wantedExtTypes);
}
// AuthorityInfoAccess
extType = Extension.authorityInfoAccess;
extControl = controls.remove(extType);
if (extControl != null && addMe(extType, extControl, neededExtTypes, wantedExtTypes)) {
AuthorityInfoAccessControl aiaControl = certprofile.getAiaControl();
List<String> caIssuers = null;
if (aiaControl == null || aiaControl.isIncludesCaIssuers()) {
caIssuers = publicCaInfo.getCaCertUris();
}
List<String> ocspUris = null;
if (aiaControl == null || aiaControl.isIncludesOcsp()) {
ocspUris = publicCaInfo.getOcspUris();
}
if (CollectionUtil.isNonEmpty(caIssuers) || CollectionUtil.isNonEmpty(ocspUris)) {
AuthorityInformationAccess value = CaUtil.createAuthorityInformationAccess(caIssuers, ocspUris);
addExtension(values, extType, value, extControl, neededExtTypes, wantedExtTypes);
}
}
if (controls.containsKey(Extension.cRLDistributionPoints) || controls.containsKey(Extension.freshestCRL)) {
X500Name crlSignerSubject = (crlSignerCert == null) ? null : X500Name.getInstance(crlSignerCert.getSubjectX500Principal().getEncoded());
X500Name x500CaPrincipal = publicCaInfo.getX500Subject();
// CRLDistributionPoints
extType = Extension.cRLDistributionPoints;
extControl = controls.remove(extType);
if (extControl != null && addMe(extType, extControl, neededExtTypes, wantedExtTypes)) {
if (CollectionUtil.isNonEmpty(publicCaInfo.getCrlUris())) {
CRLDistPoint value = CaUtil.createCrlDistributionPoints(publicCaInfo.getCrlUris(), x500CaPrincipal, crlSignerSubject);
addExtension(values, extType, value, extControl, neededExtTypes, wantedExtTypes);
}
}
// FreshestCRL
extType = Extension.freshestCRL;
extControl = controls.remove(extType);
if (extControl != null && addMe(extType, extControl, neededExtTypes, wantedExtTypes)) {
if (CollectionUtil.isNonEmpty(publicCaInfo.getDeltaCrlUris())) {
CRLDistPoint value = CaUtil.createCrlDistributionPoints(publicCaInfo.getDeltaCrlUris(), x500CaPrincipal, crlSignerSubject);
addExtension(values, extType, value, extControl, neededExtTypes, wantedExtTypes);
}
}
}
// BasicConstraints
extType = Extension.basicConstraints;
extControl = controls.remove(extType);
if (extControl != null && addMe(extType, extControl, neededExtTypes, wantedExtTypes)) {
BasicConstraints value = CaUtil.createBasicConstraints(certprofile.getCertLevel(), certprofile.getPathLenBasicConstraint());
addExtension(values, extType, value, extControl, neededExtTypes, wantedExtTypes);
}
// KeyUsage
extType = Extension.keyUsage;
extControl = controls.remove(extType);
if (extControl != null && addMe(extType, extControl, neededExtTypes, wantedExtTypes)) {
Set<KeyUsage> usages = new HashSet<>();
Set<KeyUsageControl> usageOccs = certprofile.getKeyUsage();
for (KeyUsageControl k : usageOccs) {
if (k.isRequired()) {
usages.add(k.getKeyUsage());
}
}
// the optional KeyUsage will only be set if requested explicitly
if (requestedExtensions != null && extControl.isRequest()) {
addRequestedKeyusage(usages, requestedExtensions, usageOccs);
}
org.bouncycastle.asn1.x509.KeyUsage value = X509Util.createKeyUsage(usages);
addExtension(values, extType, value, extControl, neededExtTypes, wantedExtTypes);
}
// ExtendedKeyUsage
extType = Extension.extendedKeyUsage;
extControl = controls.remove(extType);
if (extControl != null && addMe(extType, extControl, neededExtTypes, wantedExtTypes)) {
List<ASN1ObjectIdentifier> usages = new LinkedList<>();
Set<ExtKeyUsageControl> usageOccs = certprofile.getExtendedKeyUsages();
for (ExtKeyUsageControl k : usageOccs) {
if (k.isRequired()) {
usages.add(k.getExtKeyUsage());
}
}
// the optional ExtKeyUsage will only be set if requested explicitly
if (requestedExtensions != null && extControl.isRequest()) {
addRequestedExtKeyusage(usages, requestedExtensions, usageOccs);
}
if (extControl.isCritical() && usages.contains(ObjectIdentifiers.id_anyExtendedKeyUsage)) {
extControl = new ExtensionControl(false, extControl.isRequired(), extControl.isRequest());
}
ExtendedKeyUsage value = X509Util.createExtendedUsage(usages);
addExtension(values, extType, value, extControl, neededExtTypes, wantedExtTypes);
}
// ocsp-nocheck
extType = ObjectIdentifiers.id_extension_pkix_ocsp_nocheck;
extControl = controls.remove(extType);
if (extControl != null && addMe(extType, extControl, neededExtTypes, wantedExtTypes)) {
// the extension ocsp-nocheck will only be set if requested explicitly
DERNull value = DERNull.INSTANCE;
addExtension(values, extType, value, extControl, neededExtTypes, wantedExtTypes);
}
// SubjectInfoAccess
extType = Extension.subjectInfoAccess;
extControl = controls.remove(extType);
if (extControl != null && addMe(extType, extControl, neededExtTypes, wantedExtTypes)) {
ASN1Sequence value = null;
if (requestedExtensions != null && extControl.isRequest()) {
value = createSubjectInfoAccess(requestedExtensions, certprofile.getSubjectInfoAccessModes());
}
addExtension(values, extType, value, extControl, neededExtTypes, wantedExtTypes);
}
// remove extensions that are not required frrom the list
List<ASN1ObjectIdentifier> listToRm = null;
for (ASN1ObjectIdentifier extnType : controls.keySet()) {
ExtensionControl ctrl = controls.get(extnType);
if (ctrl.isRequired()) {
continue;
}
if (neededExtTypes.contains(extnType) || wantedExtTypes.contains(extnType)) {
continue;
}
if (listToRm == null) {
listToRm = new LinkedList<>();
}
listToRm.add(extnType);
}
if (listToRm != null) {
for (ASN1ObjectIdentifier extnType : listToRm) {
controls.remove(extnType);
}
}
ExtensionValues subvalues = certprofile.getExtensions(Collections.unmodifiableMap(controls), requestedSubject, grantedSubject, requestedExtensions, notBefore, notAfter, publicCaInfo);
Set<ASN1ObjectIdentifier> extTypes = new HashSet<>(controls.keySet());
for (ASN1ObjectIdentifier type : extTypes) {
extControl = controls.remove(type);
boolean addMe = addMe(type, extControl, neededExtTypes, wantedExtTypes);
if (addMe) {
ExtensionValue value = null;
if (requestedExtensions != null && extControl.isRequest()) {
Extension reqExt = requestedExtensions.getExtension(type);
if (reqExt != null) {
value = new ExtensionValue(reqExt.isCritical(), reqExt.getParsedValue());
}
}
if (value == null) {
value = subvalues.getExtensionValue(type);
}
addExtension(values, type, value, extControl, neededExtTypes, wantedExtTypes);
}
}
Set<ASN1ObjectIdentifier> unprocessedExtTypes = new HashSet<>();
for (ASN1ObjectIdentifier type : controls.keySet()) {
if (controls.get(type).isRequired()) {
unprocessedExtTypes.add(type);
}
}
if (CollectionUtil.isNonEmpty(unprocessedExtTypes)) {
throw new CertprofileException("could not add required extensions " + toString(unprocessedExtTypes));
}
if (CollectionUtil.isNonEmpty(neededExtTypes)) {
throw new BadCertTemplateException("could not add requested extensions " + toString(neededExtTypes));
}
return values;
}
use of org.xipki.ca.api.profile.CertprofileException in project xipki by xipki.
the class XmlX509Certprofile method getExtensions.
@Override
public ExtensionValues getExtensions(Map<ASN1ObjectIdentifier, ExtensionControl> extensionOccurences, X500Name requestedSubject, X500Name grantedSubject, Extensions requestedExtensions, Date notBefore, Date notAfter, PublicCaInfo caInfo) throws CertprofileException, BadCertTemplateException {
ExtensionValues values = new ExtensionValues();
if (CollectionUtil.isEmpty(extensionOccurences)) {
return values;
}
ParamUtil.requireNonNull("requestedSubject", requestedSubject);
ParamUtil.requireNonNull("notBefore", notBefore);
ParamUtil.requireNonNull("notAfter", notAfter);
Set<ASN1ObjectIdentifier> occurences = new HashSet<>(extensionOccurences.keySet());
// AuthorityKeyIdentifier
// processed by the CA
// SubjectKeyIdentifier
// processed by the CA
// KeyUsage
// processed by the CA
// CertificatePolicies
ASN1ObjectIdentifier type = Extension.certificatePolicies;
if (certificatePolicies != null) {
if (occurences.remove(type)) {
values.addExtension(type, certificatePolicies);
}
}
// Policy Mappings
type = Extension.policyMappings;
if (policyMappings != null) {
if (occurences.remove(type)) {
values.addExtension(type, policyMappings);
}
}
// SubjectAltName
type = Extension.subjectAlternativeName;
if (occurences.contains(type)) {
GeneralNames genNames = createRequestedSubjectAltNames(requestedSubject, grantedSubject, requestedExtensions);
if (genNames != null) {
ExtensionValue value = new ExtensionValue(extensionControls.get(type).isCritical(), genNames);
values.addExtension(type, value);
occurences.remove(type);
}
}
// IssuerAltName
// processed by the CA
// Subject Directory Attributes
type = Extension.subjectDirectoryAttributes;
if (occurences.contains(type) && subjectDirAttrsControl != null) {
Extension extension = (requestedExtensions == null) ? null : requestedExtensions.getExtension(type);
if (extension == null) {
throw new BadCertTemplateException("no SubjectDirecotryAttributes extension is contained in the request");
}
ASN1GeneralizedTime dateOfBirth = null;
String placeOfBirth = null;
String gender = null;
List<String> countryOfCitizenshipList = new LinkedList<>();
List<String> countryOfResidenceList = new LinkedList<>();
Map<ASN1ObjectIdentifier, List<ASN1Encodable>> otherAttrs = new HashMap<>();
Vector<?> reqSubDirAttrs = SubjectDirectoryAttributes.getInstance(extension.getParsedValue()).getAttributes();
final int n = reqSubDirAttrs.size();
for (int i = 0; i < n; i++) {
Attribute attr = (Attribute) reqSubDirAttrs.get(i);
ASN1ObjectIdentifier attrType = attr.getAttrType();
ASN1Encodable attrVal = attr.getAttributeValues()[0];
if (ObjectIdentifiers.DN_DATE_OF_BIRTH.equals(attrType)) {
dateOfBirth = ASN1GeneralizedTime.getInstance(attrVal);
} else if (ObjectIdentifiers.DN_PLACE_OF_BIRTH.equals(attrType)) {
placeOfBirth = DirectoryString.getInstance(attrVal).getString();
} else if (ObjectIdentifiers.DN_GENDER.equals(attrType)) {
gender = DERPrintableString.getInstance(attrVal).getString();
} else if (ObjectIdentifiers.DN_COUNTRY_OF_CITIZENSHIP.equals(attrType)) {
String country = DERPrintableString.getInstance(attrVal).getString();
countryOfCitizenshipList.add(country);
} else if (ObjectIdentifiers.DN_COUNTRY_OF_RESIDENCE.equals(attrType)) {
String country = DERPrintableString.getInstance(attrVal).getString();
countryOfResidenceList.add(country);
} else {
List<ASN1Encodable> otherAttrVals = otherAttrs.get(attrType);
if (otherAttrVals == null) {
otherAttrVals = new LinkedList<>();
otherAttrs.put(attrType, otherAttrVals);
}
otherAttrVals.add(attrVal);
}
}
Vector<Attribute> attrs = new Vector<>();
for (ASN1ObjectIdentifier attrType : subjectDirAttrsControl.getTypes()) {
if (ObjectIdentifiers.DN_DATE_OF_BIRTH.equals(attrType)) {
if (dateOfBirth != null) {
String timeStirng = dateOfBirth.getTimeString();
if (!SubjectDnSpec.PATTERN_DATE_OF_BIRTH.matcher(timeStirng).matches()) {
throw new BadCertTemplateException("invalid dateOfBirth " + timeStirng);
}
attrs.add(new Attribute(attrType, new DERSet(dateOfBirth)));
continue;
}
} else if (ObjectIdentifiers.DN_PLACE_OF_BIRTH.equals(attrType)) {
if (placeOfBirth != null) {
ASN1Encodable attrVal = new DERUTF8String(placeOfBirth);
attrs.add(new Attribute(attrType, new DERSet(attrVal)));
continue;
}
} else if (ObjectIdentifiers.DN_GENDER.equals(attrType)) {
if (gender != null && !gender.isEmpty()) {
char ch = gender.charAt(0);
if (!(gender.length() == 1 && (ch == 'f' || ch == 'F' || ch == 'm' || ch == 'M'))) {
throw new BadCertTemplateException("invalid gender " + gender);
}
ASN1Encodable attrVal = new DERPrintableString(gender);
attrs.add(new Attribute(attrType, new DERSet(attrVal)));
continue;
}
} else if (ObjectIdentifiers.DN_COUNTRY_OF_CITIZENSHIP.equals(attrType)) {
if (!countryOfCitizenshipList.isEmpty()) {
for (String country : countryOfCitizenshipList) {
if (!SubjectDnSpec.isValidCountryAreaCode(country)) {
throw new BadCertTemplateException("invalid countryOfCitizenship code " + country);
}
ASN1Encodable attrVal = new DERPrintableString(country);
attrs.add(new Attribute(attrType, new DERSet(attrVal)));
}
continue;
}
} else if (ObjectIdentifiers.DN_COUNTRY_OF_RESIDENCE.equals(attrType)) {
if (!countryOfResidenceList.isEmpty()) {
for (String country : countryOfResidenceList) {
if (!SubjectDnSpec.isValidCountryAreaCode(country)) {
throw new BadCertTemplateException("invalid countryOfResidence code " + country);
}
ASN1Encodable attrVal = new DERPrintableString(country);
attrs.add(new Attribute(attrType, new DERSet(attrVal)));
}
continue;
}
} else if (otherAttrs.containsKey(attrType)) {
for (ASN1Encodable attrVal : otherAttrs.get(attrType)) {
attrs.add(new Attribute(attrType, new DERSet(attrVal)));
}
continue;
}
throw new BadCertTemplateException("could not process type " + attrType.getId() + " in extension SubjectDirectoryAttributes");
}
SubjectDirectoryAttributes subjDirAttrs = new SubjectDirectoryAttributes(attrs);
ExtensionValue extValue = new ExtensionValue(extensionControls.get(type).isCritical(), subjDirAttrs);
values.addExtension(type, extValue);
occurences.remove(type);
}
// Basic Constraints
// processed by the CA
// Name Constraints
type = Extension.nameConstraints;
if (nameConstraints != null) {
if (occurences.remove(type)) {
values.addExtension(type, nameConstraints);
}
}
// PolicyConstrains
type = Extension.policyConstraints;
if (policyConstraints != null) {
if (occurences.remove(type)) {
values.addExtension(type, policyConstraints);
}
}
// ExtendedKeyUsage
// processed by CA
// CRL Distribution Points
// processed by the CA
// Inhibit anyPolicy
type = Extension.inhibitAnyPolicy;
if (inhibitAnyPolicy != null) {
if (occurences.remove(type)) {
values.addExtension(type, inhibitAnyPolicy);
}
}
// Freshest CRL
// processed by the CA
// Authority Information Access
// processed by the CA
// Subject Information Access
// processed by the CA
// Admission
type = ObjectIdentifiers.id_extension_admission;
if (occurences.contains(type) && admission != null) {
if (admission.isInputFromRequestRequired()) {
Extension extension = (requestedExtensions == null) ? null : requestedExtensions.getExtension(type);
if (extension == null) {
throw new BadCertTemplateException("No Admission extension is contained in the request");
}
Admissions[] reqAdmissions = org.bouncycastle.asn1.isismtt.x509.AdmissionSyntax.getInstance(extension.getParsedValue()).getContentsOfAdmissions();
final int n = reqAdmissions.length;
List<List<String>> reqRegNumsList = new ArrayList<>(n);
for (int i = 0; i < n; i++) {
Admissions reqAdmission = reqAdmissions[i];
ProfessionInfo[] reqPis = reqAdmission.getProfessionInfos();
List<String> reqNums = new ArrayList<>(reqPis.length);
reqRegNumsList.add(reqNums);
for (ProfessionInfo reqPi : reqPis) {
String reqNum = reqPi.getRegistrationNumber();
reqNums.add(reqNum);
}
}
values.addExtension(type, admission.getExtensionValue(reqRegNumsList));
occurences.remove(type);
} else {
values.addExtension(type, admission.getExtensionValue(null));
occurences.remove(type);
}
}
// OCSP Nocheck
// processed by the CA
// restriction
type = ObjectIdentifiers.id_extension_restriction;
if (restriction != null) {
if (occurences.remove(type)) {
values.addExtension(type, restriction);
}
}
// AdditionalInformation
type = ObjectIdentifiers.id_extension_additionalInformation;
if (additionalInformation != null) {
if (occurences.remove(type)) {
values.addExtension(type, additionalInformation);
}
}
// ValidityModel
type = ObjectIdentifiers.id_extension_validityModel;
if (validityModel != null) {
if (occurences.remove(type)) {
values.addExtension(type, validityModel);
}
}
// PrivateKeyUsagePeriod
type = Extension.privateKeyUsagePeriod;
if (occurences.contains(type)) {
Date tmpNotAfter;
if (privateKeyUsagePeriod == null) {
tmpNotAfter = notAfter;
} else {
tmpNotAfter = privateKeyUsagePeriod.add(notBefore);
if (tmpNotAfter.after(notAfter)) {
tmpNotAfter = notAfter;
}
}
ASN1EncodableVector vec = new ASN1EncodableVector();
vec.add(new DERTaggedObject(false, 0, new DERGeneralizedTime(notBefore)));
vec.add(new DERTaggedObject(false, 1, new DERGeneralizedTime(tmpNotAfter)));
ExtensionValue extValue = new ExtensionValue(extensionControls.get(type).isCritical(), new DERSequence(vec));
values.addExtension(type, extValue);
occurences.remove(type);
}
// QCStatements
type = Extension.qCStatements;
if (occurences.contains(type) && (qcStatments != null || qcStatementsOption != null)) {
if (qcStatments != null) {
values.addExtension(type, qcStatments);
occurences.remove(type);
} else if (requestedExtensions != null && qcStatementsOption != null) {
// extract the euLimit data from request
Extension extension = requestedExtensions.getExtension(type);
if (extension == null) {
throw new BadCertTemplateException("No QCStatement extension is contained in the request");
}
ASN1Sequence seq = ASN1Sequence.getInstance(extension.getParsedValue());
Map<String, int[]> qcEuLimits = new HashMap<>();
final int n = seq.size();
for (int i = 0; i < n; i++) {
QCStatement stmt = QCStatement.getInstance(seq.getObjectAt(i));
if (!ObjectIdentifiers.id_etsi_qcs_QcLimitValue.equals(stmt.getStatementId())) {
continue;
}
MonetaryValue monetaryValue = MonetaryValue.getInstance(stmt.getStatementInfo());
int amount = monetaryValue.getAmount().intValue();
int exponent = monetaryValue.getExponent().intValue();
Iso4217CurrencyCode currency = monetaryValue.getCurrency();
String currencyS = currency.isAlphabetic() ? currency.getAlphabetic().toUpperCase() : Integer.toString(currency.getNumeric());
qcEuLimits.put(currencyS, new int[] { amount, exponent });
}
ASN1EncodableVector vec = new ASN1EncodableVector();
for (QcStatementOption m : qcStatementsOption) {
if (m.getStatement() != null) {
vec.add(m.getStatement());
continue;
}
MonetaryValueOption monetaryOption = m.getMonetaryValueOption();
String currencyS = monetaryOption.getCurrencyString();
int[] limit = qcEuLimits.get(currencyS);
if (limit == null) {
throw new BadCertTemplateException("no EuLimitValue is specified for currency '" + currencyS + "'");
}
int amount = limit[0];
Range2Type range = monetaryOption.getAmountRange();
if (amount < range.getMin() || amount > range.getMax()) {
throw new BadCertTemplateException("amount for currency '" + currencyS + "' is not within [" + range.getMin() + ", " + range.getMax() + "]");
}
int exponent = limit[1];
range = monetaryOption.getExponentRange();
if (exponent < range.getMin() || exponent > range.getMax()) {
throw new BadCertTemplateException("exponent for currency '" + currencyS + "' is not within [" + range.getMin() + ", " + range.getMax() + "]");
}
MonetaryValue monetaryVale = new MonetaryValue(monetaryOption.getCurrency(), amount, exponent);
QCStatement qcStatment = new QCStatement(m.getStatementId(), monetaryVale);
vec.add(qcStatment);
}
ExtensionValue extValue = new ExtensionValue(extensionControls.get(type).isCritical(), new DERSequence(vec));
values.addExtension(type, extValue);
occurences.remove(type);
} else {
throw new RuntimeException("should not reach here");
}
}
// BiometricData
type = Extension.biometricInfo;
if (occurences.contains(type) && biometricInfo != null) {
Extension extension = (requestedExtensions == null) ? null : requestedExtensions.getExtension(type);
if (extension == null) {
throw new BadCertTemplateException("no biometricInfo extension is contained in the request");
}
ASN1Sequence seq = ASN1Sequence.getInstance(extension.getParsedValue());
final int n = seq.size();
if (n < 1) {
throw new BadCertTemplateException("biometricInfo extension in request contains empty sequence");
}
ASN1EncodableVector vec = new ASN1EncodableVector();
for (int i = 0; i < n; i++) {
BiometricData bd = BiometricData.getInstance(seq.getObjectAt(i));
TypeOfBiometricData bdType = bd.getTypeOfBiometricData();
if (!biometricInfo.isTypePermitted(bdType)) {
throw new BadCertTemplateException("biometricInfo[" + i + "].typeOfBiometricData is not permitted");
}
ASN1ObjectIdentifier hashAlgo = bd.getHashAlgorithm().getAlgorithm();
if (!biometricInfo.isHashAlgorithmPermitted(hashAlgo)) {
throw new BadCertTemplateException("biometricInfo[" + i + "].hashAlgorithm is not permitted");
}
int expHashValueSize;
try {
expHashValueSize = AlgorithmUtil.getHashOutputSizeInOctets(hashAlgo);
} catch (NoSuchAlgorithmException ex) {
throw new CertprofileException("should not happen, unknown hash algorithm " + hashAlgo);
}
byte[] hashValue = bd.getBiometricDataHash().getOctets();
if (hashValue.length != expHashValueSize) {
throw new BadCertTemplateException("biometricInfo[" + i + "].biometricDataHash has incorrect length");
}
DERIA5String sourceDataUri = bd.getSourceDataUri();
switch(biometricInfo.getSourceDataUriOccurrence()) {
case FORBIDDEN:
sourceDataUri = null;
break;
case REQUIRED:
if (sourceDataUri == null) {
throw new BadCertTemplateException("biometricInfo[" + i + "].sourceDataUri is not specified in request but is required");
}
break;
case OPTIONAL:
break;
default:
throw new BadCertTemplateException("could not reach here, unknown tripleState");
}
AlgorithmIdentifier newHashAlg = new AlgorithmIdentifier(hashAlgo, DERNull.INSTANCE);
BiometricData newBiometricData = new BiometricData(bdType, newHashAlg, new DEROctetString(hashValue), sourceDataUri);
vec.add(newBiometricData);
}
ExtensionValue extValue = new ExtensionValue(extensionControls.get(type).isCritical(), new DERSequence(vec));
values.addExtension(type, extValue);
occurences.remove(type);
}
// TlsFeature
type = ObjectIdentifiers.id_pe_tlsfeature;
if (tlsFeature != null) {
if (occurences.remove(type)) {
values.addExtension(type, tlsFeature);
}
}
// AuthorizationTemplate
type = ObjectIdentifiers.id_xipki_ext_authorizationTemplate;
if (authorizationTemplate != null) {
if (occurences.remove(type)) {
values.addExtension(type, authorizationTemplate);
}
}
// SMIME
type = ObjectIdentifiers.id_smimeCapabilities;
if (smimeCapabilities != null) {
if (occurences.remove(type)) {
values.addExtension(type, smimeCapabilities);
}
}
// constant extensions
if (constantExtensions != null) {
for (ASN1ObjectIdentifier m : constantExtensions.keySet()) {
if (!occurences.remove(m)) {
continue;
}
ExtensionValue extensionValue = constantExtensions.get(m);
if (extensionValue != null) {
values.addExtension(m, extensionValue);
}
}
}
ExtensionValues extraExtensions = getExtraExtensions(extensionOccurences, requestedSubject, grantedSubject, requestedExtensions, notBefore, notAfter, caInfo);
if (extraExtensions != null) {
for (ASN1ObjectIdentifier m : extraExtensions.getExtensionTypes()) {
values.addExtension(m, extraExtensions.getExtensionValue(m));
}
}
return values;
}
Aggregations