static JsonObject getJwk(PublicKey publicKey, String algHeader) { if (publicKey instanceof RSAPublicKey) { RSAPublicKey rsaPublicKey = (RSAPublicKey) publicKey; return Json.createObjectBuilder() .add(EXPONENT, base64UrlEncode(rsaPublicKey.getPublicExponent().toByteArray())) .add(KEY_TYPE, "RSA") .add(MODULUS, base64UrlEncode(modulusToByteArray(rsaPublicKey.getModulus()))) .build(); } else if (publicKey instanceof ECPublicKey) { ECPublicKey ecPublicKey = (ECPublicKey) publicKey; int fieldSize = ecPublicKey.getParams().getCurve().getField().getFieldSize(); return Json.createObjectBuilder() .add(CURVE, getCurveParameterFromAlgHeader(algHeader)) .add(KEY_TYPE, "EC") .add(X_COORDINATE, base64UrlEncode(coordinateToByteArray(fieldSize, ecPublicKey.getW().getAffineX()))) .add(Y_COORDINATE, base64UrlEncode(coordinateToByteArray(fieldSize, ecPublicKey.getW().getAffineY()))) .build(); } else { throw acme.unsupportedAcmeAccountPublicKeyType(publicKey.getAlgorithm()); } }
/** * Change the key that is associated with the given ACME account. * * @param account the ACME account information to use (must not be {@code null}) * @param staging whether or not the staging server URL should be used * @param certificate the new certificate to associate with the given ACME account (must not be {@code null}) * @param privateKey the new private key to associate with the given ACME account (must not be {@code null}) * @throws AcmeException if an error occurs while attempting to change the key that is associated with the given ACME account */ public void changeAccountKey(AcmeAccount account, boolean staging, X509Certificate certificate, PrivateKey privateKey) throws AcmeException { Assert.checkNotNullParam("account", account); Assert.checkNotNullParam("certificate", certificate); Assert.checkNotNullParam("privateKey", privateKey); final String keyChangeUrl = getResourceUrl(account, AcmeResource.KEY_CHANGE, staging).toString(); final String signatureAlgorithm = getDefaultCompatibleSignatureAlgorithmName(privateKey); final String algHeader = getAlgHeaderFromSignatureAlgorithm(signatureAlgorithm); final String innerEncodedProtectedHeader = getEncodedProtectedHeader(algHeader, certificate.getPublicKey(), keyChangeUrl); JsonObjectBuilder innerPayloadBuilder = Json.createObjectBuilder() .add(ACCOUNT, getAccountUrl(account, staging)) .add(OLD_KEY, getJwk(account.getPublicKey(), account.getAlgHeader())); final String innerEncodedPayload = getEncodedJson(innerPayloadBuilder.build()); final String innerEncodedSignature = getEncodedSignature(privateKey, signatureAlgorithm, innerEncodedProtectedHeader, innerEncodedPayload); final String outerEncodedPayload = getEncodedJson(getJws(innerEncodedProtectedHeader, innerEncodedPayload, innerEncodedSignature)); sendPostRequestWithRetries(account, staging, keyChangeUrl, false, outerEncodedPayload, HttpURLConnection.HTTP_OK); account.changeCertificateAndPrivateKey(certificate, privateKey); // update account info }
private String getEncodedProtectedHeader(boolean useJwk, String resourceUrl, AcmeAccount account, boolean staging) throws AcmeException { JsonObjectBuilder protectedHeaderBuilder = Json.createObjectBuilder().add(ALG, account.getAlgHeader()); if (useJwk) { protectedHeaderBuilder.add(JWK, getJwk(account.getPublicKey(), account.getAlgHeader())); } else { protectedHeaderBuilder.add(KID, getAccountUrl(account, staging)); } protectedHeaderBuilder .add(NONCE, base64UrlEncode(getNonce(account, staging))) .add(URL, resourceUrl); return getEncodedJson(protectedHeaderBuilder.build()); }
System.arraycopy(r, rLength - rActual, concatenatedSignatureBytes, rawLength - rActual, rActual); System.arraycopy(s, sLength - sActual, concatenatedSignatureBytes, 2 * rawLength - sActual, sActual); return base64UrlEncode(concatenatedSignatureBytes); return base64UrlEncode(signatureBytes); } catch (SignatureException e) { throw acme.unableToCreateAcmeSignature(e);
/** * Change the certificate and private key associated with this account. * * @param certificate the new certificate (must not be {@code null}) * @param privateKey the new private key (must not be {@code null}) */ public void changeCertificateAndPrivateKey(X509Certificate certificate, PrivateKey privateKey) { Assert.checkNotNullParam("certificate", certificate); Assert.checkNotNullParam("privateKey", privateKey); this.certificate = certificate; this.privateKey = privateKey; keySize = KeyUtil.getKeySize(privateKey); keyAlgorithmName = privateKey.getAlgorithm(); signatureAlgorithm = getDefaultCompatibleSignatureAlgorithmName(privateKey); algHeader = getAlgHeaderFromSignatureAlgorithm(signatureAlgorithm); dn = certificate.getSubjectX500Principal(); }
private static byte[] coordinateToByteArray(int fieldSize, BigInteger coordinate) { byte[] coordinateByteArray = modulusToByteArray(coordinate); int fullSize = (int) Math.ceil(fieldSize / 8d); if (fullSize > coordinateByteArray.length) { final byte[] fullSizeCoordinateByteArray = new byte[fullSize]; System.arraycopy(coordinateByteArray, 0, fullSizeCoordinateByteArray, fullSize - coordinateByteArray.length, coordinateByteArray.length); return fullSizeCoordinateByteArray; } else { return coordinateByteArray; } }
private static String getEncodedProtectedHeader(String algHeader, PublicKey publicKey, String resourceUrl) { JsonObject protectedHeader = Json.createObjectBuilder() .add(ALG, algHeader) .add(JWK, getJwk(publicKey, algHeader)) .add(URL, resourceUrl) .build(); return getEncodedJson(protectedHeader); }
/** * Get the key authorization string for this challenge. * * @param account the ACME account information to use (must not be {@code null}) * @return the key authorization string for this challenge * @throws AcmeException if the key authorization string cannot be determined */ public String getKeyAuthorization(AcmeAccount account) throws AcmeException { Assert.checkNotNullParam("account", account); JsonObject jwk = getJwk(account.getPublicKey(), account.getAlgHeader()); byte[] jwkWithoutWhitespace = CodePointIterator.ofString(jwk.toString()).skip(Character::isWhitespace).skipCrLf().asUtf8().drain(); try { MessageDigest messageDigest = MessageDigest.getInstance("SHA-256"); messageDigest.update(jwkWithoutWhitespace); byte[] jwkThumbprint = messageDigest.digest(); return token + "." + base64UrlEncode(jwkThumbprint); } catch (NoSuchAlgorithmException e) { throw acme.unableToDetermineKeyAuthorizationString(e); } }
/** * Revoke the given certificate. * * @param account the ACME account information to use (must not be {@code null}) * @param staging whether or not the staging server URL should be used * @param certificate the certificate to be revoked (must not be {@code null}) * @param reason the optional reason why the certificate is being revoked (may be {@code null}) * @throws AcmeException if an error occurs while attempting to revoke the given certificate */ public void revokeCertificate(AcmeAccount account, boolean staging, X509Certificate certificate, CRLReason reason) throws AcmeException { Assert.checkNotNullParam("account", account); Assert.checkNotNullParam("certificate", certificate); final String revokeCertUrl = getResourceUrl(account, AcmeResource.REVOKE_CERT, staging).toString(); byte[] encodedCertificate; try { encodedCertificate = certificate.getEncoded(); } catch (CertificateEncodingException e) { throw acme.unableToGetEncodedFormOfCertificateToBeRevoked(e); } JsonObjectBuilder payloadBuilder = Json.createObjectBuilder() .add(CERTIFICATE, base64UrlEncode(encodedCertificate)); if (reason != null) { payloadBuilder.add(REASON, reason.ordinal()); } sendPostRequestWithRetries(account, staging, revokeCertUrl, false, getEncodedJson(payloadBuilder.build()), HttpURLConnection.HTTP_OK); }
throw log.unableToDetermineDefaultCompatibleSignatureAlgorithmName(privateKey.getAlgorithm()); algHeader = getAlgHeaderFromSignatureAlgorithm(signatureAlgorithm); dn = certificate.getSubjectX500Principal(); } else { throw log.unableToDetermineDefaultCompatibleSignatureAlgorithmName(privateKey.getAlgorithm()); algHeader = getAlgHeaderFromSignatureAlgorithm(signatureAlgorithm); } catch (Exception e) { throw acme.acmeAccountKeyPairGenerationFailed(e);
private static byte[] coordinateToByteArray(int fieldSize, BigInteger coordinate) { byte[] coordinateByteArray = modulusToByteArray(coordinate); int fullSize = (int) Math.ceil(fieldSize / 8d); if (fullSize > coordinateByteArray.length) { final byte[] fullSizeCoordinateByteArray = new byte[fullSize]; System.arraycopy(coordinateByteArray, 0, fullSizeCoordinateByteArray, fullSize - coordinateByteArray.length, coordinateByteArray.length); return fullSizeCoordinateByteArray; } else { return coordinateByteArray; } }
private static String getEncodedProtectedHeader(String algHeader, PublicKey publicKey, String resourceUrl) { JsonObject protectedHeader = Json.createObjectBuilder() .add(ALG, algHeader) .add(JWK, getJwk(publicKey, algHeader)) .add(URL, resourceUrl) .build(); return getEncodedJson(protectedHeader); }
static JsonObject getJwk(PublicKey publicKey, String algHeader) { if (publicKey instanceof RSAPublicKey) { RSAPublicKey rsaPublicKey = (RSAPublicKey) publicKey; return Json.createObjectBuilder() .add(EXPONENT, base64UrlEncode(rsaPublicKey.getPublicExponent().toByteArray())) .add(KEY_TYPE, "RSA") .add(MODULUS, base64UrlEncode(modulusToByteArray(rsaPublicKey.getModulus()))) .build(); } else if (publicKey instanceof ECPublicKey) { ECPublicKey ecPublicKey = (ECPublicKey) publicKey; int fieldSize = ecPublicKey.getParams().getCurve().getField().getFieldSize(); return Json.createObjectBuilder() .add(CURVE, getCurveParameterFromAlgHeader(algHeader)) .add(KEY_TYPE, "EC") .add(X_COORDINATE, base64UrlEncode(coordinateToByteArray(fieldSize, ecPublicKey.getW().getAffineX()))) .add(Y_COORDINATE, base64UrlEncode(coordinateToByteArray(fieldSize, ecPublicKey.getW().getAffineY()))) .build(); } else { throw acme.unsupportedAcmeAccountPublicKeyType(publicKey.getAlgorithm()); } }
private String getEncodedProtectedHeader(boolean useJwk, String resourceUrl, AcmeAccount account, boolean staging) throws AcmeException { JsonObjectBuilder protectedHeaderBuilder = Json.createObjectBuilder().add(ALG, account.getAlgHeader()); if (useJwk) { protectedHeaderBuilder.add(JWK, getJwk(account.getPublicKey(), account.getAlgHeader())); } else { protectedHeaderBuilder.add(KID, getAccountUrl(account, staging)); } protectedHeaderBuilder .add(NONCE, base64UrlEncode(getNonce(account, staging))) .add(URL, resourceUrl); return getEncodedJson(protectedHeaderBuilder.build()); }
/** * Change the key that is associated with the given ACME account. * * @param account the ACME account information to use (must not be {@code null}) * @param staging whether or not the staging server URL should be used * @param certificate the new certificate to associate with the given ACME account (must not be {@code null}) * @param privateKey the new private key to associate with the given ACME account (must not be {@code null}) * @throws AcmeException if an error occurs while attempting to change the key that is associated with the given ACME account */ public void changeAccountKey(AcmeAccount account, boolean staging, X509Certificate certificate, PrivateKey privateKey) throws AcmeException { Assert.checkNotNullParam("account", account); Assert.checkNotNullParam("certificate", certificate); Assert.checkNotNullParam("privateKey", privateKey); final String keyChangeUrl = getResourceUrl(account, AcmeResource.KEY_CHANGE, staging).toString(); final String signatureAlgorithm = getDefaultCompatibleSignatureAlgorithmName(privateKey); final String algHeader = getAlgHeaderFromSignatureAlgorithm(signatureAlgorithm); final String innerEncodedProtectedHeader = getEncodedProtectedHeader(algHeader, certificate.getPublicKey(), keyChangeUrl); JsonObjectBuilder innerPayloadBuilder = Json.createObjectBuilder() .add(ACCOUNT, getAccountUrl(account, staging)) .add(OLD_KEY, getJwk(account.getPublicKey(), account.getAlgHeader())); final String innerEncodedPayload = getEncodedJson(innerPayloadBuilder.build()); final String innerEncodedSignature = getEncodedSignature(privateKey, signatureAlgorithm, innerEncodedProtectedHeader, innerEncodedPayload); final String outerEncodedPayload = getEncodedJson(getJws(innerEncodedProtectedHeader, innerEncodedPayload, innerEncodedSignature)); sendPostRequestWithRetries(account, staging, keyChangeUrl, false, outerEncodedPayload, HttpURLConnection.HTTP_OK); account.changeCertificateAndPrivateKey(certificate, privateKey); // update account info }
.add(CSR, base64UrlEncode(csrBuilder.build().getEncoded())); connection = sendPostRequestWithRetries(account, staging, finalizeOrderUrl, false, getEncodedJson(payloadBuilder.build()), HttpURLConnection.HTTP_OK); final String orderUrl = getLocation(connection);
/** * Change the certificate and private key associated with this account. * * @param certificate the new certificate (must not be {@code null}) * @param privateKey the new private key (must not be {@code null}) */ public void changeCertificateAndPrivateKey(X509Certificate certificate, PrivateKey privateKey) { Assert.checkNotNullParam("certificate", certificate); Assert.checkNotNullParam("privateKey", privateKey); this.certificate = certificate; this.privateKey = privateKey; keySize = KeyUtil.getKeySize(privateKey); keyAlgorithmName = privateKey.getAlgorithm(); signatureAlgorithm = getDefaultCompatibleSignatureAlgorithmName(privateKey); algHeader = getAlgHeaderFromSignatureAlgorithm(signatureAlgorithm); dn = certificate.getSubjectX500Principal(); }
private static byte[] coordinateToByteArray(int fieldSize, BigInteger coordinate) { byte[] coordinateByteArray = modulusToByteArray(coordinate); int fullSize = (int) Math.ceil(fieldSize / 8d); if (fullSize > coordinateByteArray.length) { final byte[] fullSizeCoordinateByteArray = new byte[fullSize]; System.arraycopy(coordinateByteArray, 0, fullSizeCoordinateByteArray, fullSize - coordinateByteArray.length, coordinateByteArray.length); return fullSizeCoordinateByteArray; } else { return coordinateByteArray; } }
private static String getEncodedProtectedHeader(String algHeader, PublicKey publicKey, String resourceUrl) { JsonObject protectedHeader = Json.createObjectBuilder() .add(ALG, algHeader) .add(JWK, getJwk(publicKey, algHeader)) .add(URL, resourceUrl) .build(); return getEncodedJson(protectedHeader); }
static JsonObject getJwk(PublicKey publicKey, String algHeader) { if (publicKey instanceof RSAPublicKey) { RSAPublicKey rsaPublicKey = (RSAPublicKey) publicKey; return Json.createObjectBuilder() .add(EXPONENT, base64UrlEncode(rsaPublicKey.getPublicExponent().toByteArray())) .add(KEY_TYPE, "RSA") .add(MODULUS, base64UrlEncode(modulusToByteArray(rsaPublicKey.getModulus()))) .build(); } else if (publicKey instanceof ECPublicKey) { ECPublicKey ecPublicKey = (ECPublicKey) publicKey; int fieldSize = ecPublicKey.getParams().getCurve().getField().getFieldSize(); return Json.createObjectBuilder() .add(CURVE, getCurveParameterFromAlgHeader(algHeader)) .add(KEY_TYPE, "EC") .add(X_COORDINATE, base64UrlEncode(coordinateToByteArray(fieldSize, ecPublicKey.getW().getAffineX()))) .add(Y_COORDINATE, base64UrlEncode(coordinateToByteArray(fieldSize, ecPublicKey.getW().getAffineY()))) .build(); } else { throw acme.unsupportedAcmeAccountPublicKeyType(publicKey.getAlgorithm()); } }