Get unique identifier according to draft-ietf-acme-ari-03

pull/168/head
Richard Körber 2024-02-18 16:16:29 +01:00
parent edb7ec83b6
commit 6a4770c23a
No known key found for this signature in database
GPG Key ID: AAB9FD19C78AA3E0
2 changed files with 70 additions and 0 deletions

View File

@ -16,21 +16,29 @@ package org.shredzone.acme4j.toolbox;
import static java.nio.charset.StandardCharsets.UTF_8; import static java.nio.charset.StandardCharsets.UTF_8;
import java.io.IOException; import java.io.IOException;
import java.io.UncheckedIOException;
import java.io.Writer; import java.io.Writer;
import java.net.IDN; import java.net.IDN;
import java.net.URI; import java.net.URI;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.security.MessageDigest; import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import java.time.Instant; import java.time.Instant;
import java.time.ZoneId; import java.time.ZoneId;
import java.time.ZonedDateTime; import java.time.ZonedDateTime;
import java.util.Arrays;
import java.util.Base64; import java.util.Base64;
import java.util.Locale; import java.util.Locale;
import java.util.Objects; import java.util.Objects;
import java.util.Optional;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import edu.umd.cs.findbugs.annotations.Nullable; import edu.umd.cs.findbugs.annotations.Nullable;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.x509.AuthorityKeyIdentifier;
import org.bouncycastle.asn1.x509.Certificate;
import org.bouncycastle.cert.X509CertificateHolder;
import org.shredzone.acme4j.exception.AcmeProtocolException; import org.shredzone.acme4j.exception.AcmeProtocolException;
/** /**
@ -323,4 +331,57 @@ public final class AcmeUtils {
} }
} }
/**
* Returns the certificate's unique identifier for renewal according to
* draft-ietf-acme-ari-03.
*
* @param certificate
* Certificate to get the unique identifier for.
* @return Unique identifier
* @throws AcmeProtocolException
* if the certificate is invalid or does not provide the necessary
* information.
*/
public static String getRenewalUniqueIdentifier(X509Certificate certificate) {
try {
var cert = new X509CertificateHolder(certificate.getEncoded());
var aki = Optional.of(cert)
.map(X509CertificateHolder::getExtensions)
.map(AuthorityKeyIdentifier::fromExtensions)
.map(AuthorityKeyIdentifier::getKeyIdentifier)
.map(AcmeUtils::base64UrlEncode)
.orElseThrow(() -> new AcmeProtocolException("Missing or invalid Authority Key Identifier"));
var sn = Optional.of(cert)
.map(X509CertificateHolder::toASN1Structure)
.map(Certificate::getSerialNumber)
.map(AcmeUtils::getRawInteger)
.map(AcmeUtils::base64UrlEncode)
.orElseThrow(() -> new AcmeProtocolException("Missing or invalid serial number"));
return aki + '.' + sn;
} catch (Exception ex) {
throw new AcmeProtocolException("Invalid certificate", ex);
}
}
/**
* Gets the raw integer array from ASN1Integer. This is done by encoding it to a byte
* array, and then skipping the INTEGER identifier. Other methods of ASN1Integer only
* deliver a parsed integer value that might have been mangled.
*
* @param integer
* ASN1Integer to convert to raw
* @return Byte array of the raw integer
*/
private static byte[] getRawInteger(ASN1Integer integer) {
try {
var encoded = integer.getEncoded();
return Arrays.copyOfRange(encoded, 2, encoded.length);
} catch (IOException ex) {
throw new UncheckedIOException(ex);
}
}
} }

View File

@ -0,0 +1,9 @@
-----BEGIN CERTIFICATE-----
MIIBQzCB66ADAgECAgUAh2VDITAKBggqhkjOPQQDAjAVMRMwEQYDVQQDEwpFeGFt
cGxlIENBMCIYDzAwMDEwMTAxMDAwMDAwWhgPMDAwMTAxMDEwMDAwMDBaMBYxFDAS
BgNVBAMTC2V4YW1wbGUuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeBZu
7cbpAYNXZLbbh8rNIzuOoqOOtmxA1v7cRm//AwyMwWxyHz4zfwmBhcSrf47NUAFf
qzLQ2PPQxdTXREYEnKMjMCEwHwYDVR0jBBgwFoAUaYhba4dGQEHhs3uEe6CuLN4B
yNQwCgYIKoZIzj0EAwIDRwAwRAIge09+S5TZAlw5tgtiVvuERV6cT4mfutXIlwTb
+FYN/8oCIClDsqBklhB9KAelFiYt9+6FDj3z4KGVelYM5MdsO3pK
-----END CERTIFICATE-----