log.debug("Received an authenticated request, could be an initial DV request signed by CVCA or a renewal for DV or IS.");
CVCAuthenticatedRequest authreq = (CVCAuthenticatedRequest)parsedObject;
CVCPublicKey cvcKey = authreq.getRequest().getCertificateBody().getPublicKey();
String algorithm = AlgorithmUtil.getAlgorithmName(cvcKey.getObjectIdentifier());
log.debug("Received request has a public key with algorithm: "+algorithm);
HolderReferenceField holderRef = authreq.getRequest().getCertificateBody().getHolderReference();
CAReferenceField caRef = authreq.getAuthorityReference();
// Check to see that the inner signature does not also verify using an old certificate
// because that means the same keys were used, and that is not allowed according to the EU policy
// This must be done whether it is signed by CVCA or a renewal request
Collection<java.security.cert.Certificate> oldcerts = certificateStoreSession.findCertificatesByUsername(admin, username);
if (oldcerts != null) {
log.debug("Found "+oldcerts.size()+" old certificates for user "+username);
Iterator<java.security.cert.Certificate> iterator = oldcerts.iterator();
while (iterator.hasNext()) {
java.security.cert.Certificate cert = iterator.next();
PublicKey pk = getCVPublicKey(admin, cert);
CVCertificate innerreq = authreq.getRequest();
checkInnerCollision(pk, innerreq, holderRef.getConcatenated()); // Throws AuthorizationDeniedException
}
}
boolean verifiedOuter = false; // So we can throw an error if we could not verify
if (StringUtils.equals(holderRef.getMnemonic(), caRef.getMnemonic()) && StringUtils.equals(holderRef.getCountry(), caRef.getCountry())) {
log.debug("Authenticated request is self signed, we will try to verify it using user's old certificate.");
Collection<java.security.cert.Certificate> certs = certificateStoreSession.findCertificatesByUsername(admin, username);
// certs contains certificates ordered with last expire date first. Last expire date should be last issued cert
// We have to iterate over available user certificates, because we don't know which on signed the old one
// and cv certificates have very coarse grained validity periods so we can't really know which one is the latest one
// if 2 certificates are issued the same day.
if (certs != null) {
log.debug("Found "+certs.size()+" old certificates for user "+username);
Iterator<java.security.cert.Certificate> iterator = certs.iterator();
while (iterator.hasNext()) {
java.security.cert.Certificate cert = iterator.next();
try {
// Only allow renewal if the old certificate is valid
PublicKey pk = getCVPublicKey(admin, cert);
if (log.isDebugEnabled()) {
log.debug("Trying to verify the outer signature with an old certificate, fp: "+CertTools.getFingerprintAsString(cert));
}
authreq.verify(pk);
log.debug("Verified outer signature");
// Yes we did it, we can move on to the next step because the outer signature was actually created with some old certificate
verifiedOuter = true;
if (ejbhelper.checkValidityAndSetUserPassword(admin, cert, username, password)) {
// If we managed to verify the certificate we will break out of the loop
break;
}
// If verification of outer signature fails because the signature is invalid we will break and deny the request...with a message
} catch (InvalidKeyException e) {
String msg = intres.getLocalizedMessage("cvc.error.outersignature", holderRef.getConcatenated(), e.getMessage());
log.warn(msg, e);
} catch (CertificateExpiredException e) { // thrown by checkValidityAndSetUserPassword
String msg = intres.getLocalizedMessage("cvc.error.outersignature", holderRef.getConcatenated(), e.getMessage());
// Only log this with DEBUG since it will be a common case that happens, nothing that should cause any alerts
log.debug(msg);
// This exception we want to throw on, because we want to give this error if there was a certificate suitable for
// verification, but it had expired. This is thrown by checkValidityAndSetUserPassword after the request has already been
// verified using the public key of the certificate.
throw e;
} catch (CertificateException e) {
String msg = intres.getLocalizedMessage("cvc.error.outersignature", holderRef.getConcatenated(), e.getMessage());
log.warn(msg, e);
} catch (NoSuchAlgorithmException e) {
String msg = intres.getLocalizedMessage("cvc.error.outersignature", holderRef.getConcatenated(), e.getMessage());
log.info(msg, e);
} catch (NoSuchProviderException e) {
String msg = intres.getLocalizedMessage("cvc.error.outersignature", holderRef.getConcatenated(), e.getMessage());
log.warn(msg, e);
} catch (SignatureException e) {
// Failing to verify the outer signature will be normal, since we must try all old certificates
if (log.isDebugEnabled()) {
String msg = intres.getLocalizedMessage("cvc.error.outersignature", holderRef.getConcatenated(), e.getMessage());
log.debug(msg);
}
}
} // while (iterator.hasNext()) {
// if verification failed because the old cert was not yet valid, continue processing as usual, using the sent in username/password hoping the
// status is NEW and password is correct. If old certificate was expired a CertificateExpiredException is thrown above.
} // if (certs != null) {
// If there are no old certificate, continue processing as usual, using the sent in username/password hoping the
// status is NEW and password is correct.
} else { // if (StringUtils.equals(holderRef, caRef))
// Subject and issuerDN is CN=Mnemonic,C=Country
String dn = "CN="+caRef.getMnemonic()+",C="+caRef.getCountry();
log.debug("Authenticated request is not self signed, we will try to verify it using a CVCA certificate: "+dn);
CAInfo info = caAdminSession.getCAInfoOrThrowException(admin, CertTools.stringToBCDNString(dn).hashCode());
if (info != null) {
Collection<java.security.cert.Certificate> certs = info.getCertificateChain();
if (certs != null) {
log.debug("Found "+certs.size()+" certificates in chain for CA with DN: "+dn);
Iterator<java.security.cert.Certificate> iterator = certs.iterator();
if (iterator.hasNext()) {
// The CA certificate is first in chain
java.security.cert.Certificate cert = iterator.next();
if (log.isDebugEnabled()) {
log.debug("Trying to verify the outer signature with a CVCA certificate, fp: "+CertTools.getFingerprintAsString(cert));
}
try {
// The CVCA certificate always contains the full key parameters, no need to du any EC curve parameter magic here
authreq.verify(cert.getPublicKey());
log.debug("Verified outer signature");
verifiedOuter = true;
// Yes we did it, we can move on to the next step because the outer signature was actually created with some old certificate
if (!ejbhelper.checkValidityAndSetUserPassword(admin, cert, username, password)) {
// If the CA certificate was not valid, we are not happy
String msg = intres.getLocalizedMessage("cvc.error.outersignature", holderRef.getConcatenated(), "CA certificate not valid for CA: "+info.getCAId());
log.info(msg);
throw new AuthorizationDeniedException(msg);
}
} catch (InvalidKeyException e) {
String msg = intres.getLocalizedMessage("cvc.error.outersignature", holderRef.getConcatenated(), e.getMessage());
log.warn(msg, e);
} catch (CertificateException e) {
String msg = intres.getLocalizedMessage("cvc.error.outersignature", holderRef.getConcatenated(), e.getMessage());
log.warn(msg, e);
} catch (NoSuchAlgorithmException e) {
String msg = intres.getLocalizedMessage("cvc.error.outersignature", holderRef.getConcatenated(), e.getMessage());
log.warn(msg, e);
} catch (NoSuchProviderException e) {
String msg = intres.getLocalizedMessage("cvc.error.outersignature", holderRef.getConcatenated(), e.getMessage());
log.warn(msg, e);
} catch (SignatureException e) {
String msg = intres.getLocalizedMessage("cvc.error.outersignature", holderRef.getConcatenated(), e.getMessage());
log.warn(msg, e);
}
}
} else {
log.info("No CA certificate found to authenticate request: "+dn);
}
} else {
log.info("No CA found to authenticate request: "+dn);
}
}
// if verification failed because we could not verify the outer signature at all it is an error
if (!verifiedOuter) {
String msg = intres.getLocalizedMessage("cvc.error.outersignature", holderRef.getConcatenated(), "No certificate found that could authenticate request");
log.info(msg);
throw new AuthorizationDeniedException(msg);
}
} // if (parsedObject instanceof CVCAuthenticatedRequest)
// If it is not an authenticated request, with an outer signature, continue processing as usual,