@@ -19014,6 +19014,39 @@ static int DecodeKeyUsageInternal(const byte* input, word32 sz,
1901419014 return DecodeKeyUsage(input, sz, &cert->extKeyUsage);
1901519015}
1901619016
19017+ #ifdef WOLFSSL_ACME_OID
19018+ /* Decodes the RFC 8737 id-pe-acmeIdentifier (1.3.6.1.5.5.7.1.31)
19019+ * extension value into cert->acmeIdentifier.
19020+ *
19021+ * The extnValue is an OCTET STRING wrapping a SHA-256 digest of the
19022+ * ACME keyAuth, per RFC 8737 3. Length is verified against
19023+ * WC_SHA256_DIGEST_SIZE.
19024+ *
19025+ * @param [in] input ASN.1 DER-encoded extension value.
19026+ * @param [in] sz Length of input in bytes.
19027+ * @param [in, out] cert DecodedCert to populate (acmeIdentifier and
19028+ * acmeIdentifierSz fields).
19029+ *
19030+ * @return 0 on success.
19031+ * @return ASN_PARSE_E when the inner OCTET STRING is missing or not
19032+ * exactly WC_SHA256_DIGEST_SIZE bytes.
19033+ */
19034+ static int DecodeAcmeId(const byte* input, word32 sz, DecodedCert* cert)
19035+ {
19036+ word32 hashIdx = 0;
19037+ int hashLen = 0;
19038+
19039+ if (GetOctetString(input, &hashIdx, &hashLen, sz) < 0)
19040+ return ASN_PARSE_E;
19041+ if (hashLen != WC_SHA256_DIGEST_SIZE)
19042+ return ASN_PARSE_E;
19043+
19044+ XMEMCPY(cert->acmeIdentifier, &input[hashIdx], WC_SHA256_DIGEST_SIZE);
19045+ cert->acmeIdentifierSz = WC_SHA256_DIGEST_SIZE;
19046+ return 0;
19047+ }
19048+ #endif /* WOLFSSL_ACME_OID */
19049+
1901719050#ifdef WOLFSSL_ASN_TEMPLATE
1901819051/* ASN.1 template for KeyPurposeId.
1901919052 * X.509: RFC 5280, 4.2.1.12 - Extended Key Usage.
@@ -20236,6 +20269,14 @@ int DecodeExtensionType(const byte* input, word32 length, word32 oid,
2023620269 return ASN_PARSE_E;
2023720270 break;
2023820271 #endif /* WOLFSSL_DUAL_ALG_CERTS */
20272+ #ifdef WOLFSSL_ACME_OID
20273+ case ACME_IDENTIFIER_OID:
20274+ VERIFY_AND_SET_OID(cert->extAcmeIdentifierSet);
20275+ cert->extAcmeIdentifierCrit = critical ? 1 : 0;
20276+ if (DecodeAcmeId(&input[idx], length, cert) < 0)
20277+ return ASN_PARSE_E;
20278+ break;
20279+ #endif
2023920280 default:
2024020281 if (isUnknownExt != NULL)
2024120282 *isUnknownExt = 1;
@@ -26510,6 +26551,12 @@ static const ASNItem static_certExtsASN[] = {
2651026551/* CRLINFO_SEQ */ { 0, ASN_SEQUENCE, 1, 1, 0 },
2651126552/* CRLINFO_OID */ { 1, ASN_OBJECT_ID, 0, 0, 0 },
2651226553/* CRLINFO_STR */ { 1, ASN_OCTET_STRING, 0, 0, 0 },
26554+ /* RFC 8737 id-pe-acmeIdentifier */
26555+ /* ACMEID_SEQ */ { 0, ASN_SEQUENCE, 1, 1, 0 },
26556+ /* ACMEID_OID */ { 1, ASN_OBJECT_ID, 0, 0, 0 },
26557+ /* ACMEID_CRIT */ { 1, ASN_BOOLEAN, 0, 0, 0 },
26558+ /* ACMEID_STR */ { 1, ASN_OCTET_STRING, 0, 1, 0 },
26559+ /* ACMEID_HASH */ { 2, ASN_OCTET_STRING, 0, 0, 0 },
2651326560#ifdef WOLFSSL_DUAL_ALG_CERTS
2651426561/* SAPKI_SEQ */ { 0, ASN_SEQUENCE, 1, 1, 0 },
2651526562/* SAPKI_OID */ { 1, ASN_OBJECT_ID, 0, 0, 0 },
@@ -26568,6 +26615,11 @@ enum {
2656826615 CERTEXTSASN_IDX_CRLINFO_SEQ,
2656926616 CERTEXTSASN_IDX_CRLINFO_OID,
2657026617 CERTEXTSASN_IDX_CRLINFO_STR,
26618+ CERTEXTSASN_IDX_ACMEID_SEQ,
26619+ CERTEXTSASN_IDX_ACMEID_OID,
26620+ CERTEXTSASN_IDX_ACMEID_CRIT,
26621+ CERTEXTSASN_IDX_ACMEID_STR,
26622+ CERTEXTSASN_IDX_ACMEID_HASH,
2657126623#ifdef WOLFSSL_DUAL_ALG_CERTS
2657226624 CERTEXTSASN_IDX_SAPKI_SEQ,
2657326625 CERTEXTSASN_IDX_SAPKI_OID,
@@ -26623,6 +26675,10 @@ static int EncodeExtensions(Cert* cert, byte* output, word32 maxSz,
2662326675 static const byte nsCertOID[] = { 0x60, 0x86, 0x48, 0x01,
2662426676 0x86, 0xF8, 0x42, 0x01, 0x01 };
2662526677 static const byte crlInfoOID[] = { 0x55, 0x1D, 0x1F };
26678+ #ifdef WOLFSSL_ACME_OID
26679+ static const byte acmeIdOID[] = { 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07,
26680+ 0x01, 0x1F };
26681+ #endif
2662626682#ifdef WOLFSSL_DUAL_ALG_CERTS
2662726683 static const byte sapkiOID[] = { 0x55, 0x1d, 0x48 };
2662826684 static const byte altSigAlgOID[] = { 0x55, 0x1d, 0x49 };
@@ -26878,6 +26934,24 @@ static int EncodeExtensions(Cert* cert, byte* output, word32 maxSz,
2687826934 CERTEXTSASN_IDX_CRLINFO_STR);
2687926935 }
2688026936
26937+ #ifdef WOLFSSL_ACME_OID
26938+ /* id-pe-acmeIdentifier (TLS-ALPN-01 challenge cert).
26939+ * Always critical=TRUE. */
26940+ if (cert->acmeIdentifierSz == WC_SHA256_DIGEST_SIZE) {
26941+ SetASN_Buffer(&dataASN[CERTEXTSASN_IDX_ACMEID_OID],
26942+ acmeIdOID, sizeof(acmeIdOID));
26943+ SetASN_Boolean(&dataASN[CERTEXTSASN_IDX_ACMEID_CRIT], 1);
26944+ SetASN_Buffer(&dataASN[CERTEXTSASN_IDX_ACMEID_HASH],
26945+ cert->acmeIdentifier, (word32)cert->acmeIdentifierSz);
26946+ }
26947+ else
26948+ #endif /* WOLFSSL_ACME_OID */
26949+ {
26950+ /* Don't write out the ACME identifier extension. */
26951+ SetASNItem_NoOut(dataASN, CERTEXTSASN_IDX_ACMEID_SEQ,
26952+ CERTEXTSASN_IDX_ACMEID_HASH);
26953+ }
26954+
2688126955 #ifdef WOLFSSL_DUAL_ALG_CERTS
2688226956 if (cert->sapkiDer != NULL) {
2688326957 /* Set subject alternative public key info OID, criticality and
@@ -29313,6 +29387,40 @@ int wc_SetExtKeyUsage(Cert *cert, const char *value)
2931329387 return ret;
2931429388}
2931529389
29390+ #ifdef WOLFSSL_ACME_OID
29391+ /* Set the id-pe-acmeIdentifier extension value from the ACME
29392+ * keyAuth string. Computes SHA-256 over keyAuth and stores the digest
29393+ * as the extension value. RFC 8737 3 requires critical=TRUE; that's
29394+ * applied at encode time in EncodeExtensions.
29395+ *
29396+ * keyAuth is the raw bytes of the key authorization string per
29397+ * RFC 8555 8.1: token "." JWK_thumbprint.
29398+ */
29399+ int wc_SetAcmeIdentifierExt(Cert *cert, const byte *keyAuth, word32 keyAuthSz)
29400+ {
29401+ int ret;
29402+ byte digest[WC_SHA256_DIGEST_SIZE];
29403+ wc_Sha256 sha;
29404+
29405+ if (cert == NULL || keyAuth == NULL || keyAuthSz == 0)
29406+ return BAD_FUNC_ARG;
29407+
29408+ ret = wc_InitSha256(&sha);
29409+ if (ret != 0)
29410+ return ret;
29411+ ret = wc_Sha256Update(&sha, keyAuth, keyAuthSz);
29412+ if (ret == 0)
29413+ ret = wc_Sha256Final(&sha, digest);
29414+ wc_Sha256Free(&sha);
29415+ if (ret != 0)
29416+ return ret;
29417+
29418+ XMEMCPY(cert->acmeIdentifier, digest, WC_SHA256_DIGEST_SIZE);
29419+ cert->acmeIdentifierSz = WC_SHA256_DIGEST_SIZE;
29420+ return 0;
29421+ }
29422+ #endif /* WOLFSSL_ACME_OID */
29423+
2931629424#ifdef WOLFSSL_EKU_OID
2931729425/*
2931829426 * cert structure to set EKU oid in
0 commit comments