Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .wolfssl_known_macro_extras
Original file line number Diff line number Diff line change
Expand Up @@ -833,7 +833,6 @@ WOLFSSL_NO_DH186
WOLFSSL_NO_DTLS_SIZE_CHECK
WOLFSSL_NO_ETM_ALERT
WOLFSSL_NO_FENCE
WOLFSSL_NO_INIT_CTX_KEY
WOLFSSL_NO_ISSUERHASH_TDPEER
WOLFSSL_NO_KCAPI_AES_CBC
WOLFSSL_NO_KCAPI_HMAC_SHA1
Expand Down
26 changes: 26 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -1298,6 +1298,7 @@ then
AC_MSG_ERROR([--enable-all-osp is incompatible with --enable-linuxkm-defaults])
fi

test "$enable_tailscale" = "" && enable_tailscale=yes
Comment thread
lealem47 marked this conversation as resolved.
test "$enable_wolfguard" = "" && enable_wolfguard=yes
test "$enable_webserver" = "" && enable_webserver=yes

Expand Down Expand Up @@ -1648,6 +1649,31 @@ then
AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_ECDSA_DETERMINISTIC_K_VARIANT"
fi

# Support for Tailscale port
AC_ARG_ENABLE([tailscale],
[AS_HELP_STRING([--enable-tailscale],[Enable Tailscale build dependencies (default: disabled)])],
[ ENABLED_TAILSCALE=$enableval ],
[ ENABLED_TAILSCALE=no ]
)
if test "$ENABLED_TAILSCALE" = "yes"
then
enable_wolfguard=yes
test "x$enable_sp" = "x" && enable_sp="yes,256"
enable_compkey=yes
enable_opensslall=yes
enable_alpn=yes
enable_sni=yes
enable_certgen=yes
enable_certreq=yes
enable_certext=yes
enable_sessioncerts=yes
enable_cert_setup_cb=yes
AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_PUBLIC_MP"
AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_NO_INIT_CTX_KEY"
AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_ALWAYS_KEEP_SNI"
AM_CFLAGS="$AM_CFLAGS -DWC_CTC_NAME_SIZE=128 -DWOLFSSL_ACME_OID"
fi
Comment thread
lealem47 marked this conversation as resolved.

# wolfGuard
AC_ARG_ENABLE([wolfguard],
[AS_HELP_STRING([--enable-wolfguard],[Enable wolfGuard dependencies (default: disabled)])],
Expand Down
85 changes: 85 additions & 0 deletions tests/api.c
Original file line number Diff line number Diff line change
Expand Up @@ -11626,6 +11626,90 @@ static int test_wolfSSL_mcast(void)
| Wolfcrypt
*----------------------------------------------------------------------------*/

/*
* Testing wc_SetAcmeIdentifierExt() round-trip - the RFC 8737
* id-pe-acmeIdentifier (1.3.6.1.5.5.7.1.31) extension used by
* TLS-ALPN-01 ACME challenge certs.
*/
static int test_wc_SetAcmeIdentifierExt(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_ACME_OID) && defined(WOLFSSL_CERT_GEN) && \
defined(HAVE_ECC) && !defined(NO_SHA256) && !defined(NO_ASN_TIME) && \
!defined(WC_NO_RNG) && !defined(NO_RSA)
Cert cert;
DecodedCert decoded;
WC_RNG rng;
ecc_key key;
byte der[TWOK_BUF];
int derSz = 0;
int rngInited = 0, keyInited = 0;
const char* keyAuth = "evaGxfADs6pSRb2LAv9IZf17Dt3juxGJ-PCt92wr-oA"
".kZdq0qaDcXNVxKBkP_uiKvw2Yg5sRJ8KBfQa9Ru13nE";
word32 keyAuthSz = (word32)XSTRLEN(keyAuth);
byte expected[WC_SHA256_DIGEST_SIZE];

XMEMSET(&cert, 0, sizeof(cert));
XMEMSET(&decoded, 0, sizeof(decoded));
XMEMSET(&rng, 0, sizeof(rng));
XMEMSET(&key, 0, sizeof(key));
XMEMSET(der, 0, sizeof(der));

/* Compute the expected digest */
ExpectIntEQ(wc_Sha256Hash((const byte*)keyAuth, keyAuthSz, expected), 0);

/* Input validation. */
ExpectIntEQ(wc_SetAcmeIdentifierExt(NULL, (const byte*)keyAuth, keyAuthSz),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_SetAcmeIdentifierExt(&cert, NULL, keyAuthSz),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_SetAcmeIdentifierExt(&cert, (const byte*)keyAuth, 0),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));

/* Build a P-256 keypair to sign the cert. */
ExpectIntEQ(wc_InitRng(&rng), 0);
rngInited = 1;
ExpectIntEQ(wc_ecc_init(&key), 0);
keyInited = 1;
ExpectIntEQ(wc_ecc_make_key_ex(&rng, KEY32, &key, ECC_SECP256R1), 0);

/* Build a minimal self-signed cert template carrying the extension. */
ExpectIntEQ(wc_InitCert(&cert), 0);
cert.sigType = CTC_SHA256wECDSA;
cert.daysValid = 1;
cert.isCA = 0;
XSTRNCPY(cert.subject.commonName, "acme-test.example", CTC_NAME_SIZE);

ExpectIntEQ(wc_SetAcmeIdentifierExt(&cert, (const byte*)keyAuth,
keyAuthSz), 0);
ExpectIntEQ(cert.acmeIdentifierSz, WC_SHA256_DIGEST_SIZE);
ExpectIntEQ(XMEMCMP(cert.acmeIdentifier, expected,
WC_SHA256_DIGEST_SIZE), 0);

/* MakeCert + SignCert. ECC_TYPE selects the ECDSA signing path. */
ExpectIntGT(derSz = wc_MakeCert_ex(&cert, der, sizeof(der),
ECC_TYPE, &key, &rng), 0);
ExpectIntGT(derSz = wc_SignCert_ex(cert.bodySz, cert.sigType,
der, sizeof(der),
ECC_TYPE, &key, &rng), 0);

/* Parse the cert back and verify the extension survives the
* round-trip via DecodeAcmeId. */
wc_InitDecodedCert(&decoded, der, derSz, NULL);
ExpectIntEQ(wc_ParseCert(&decoded, CERT_TYPE, NO_VERIFY, NULL), 0);
ExpectIntEQ(decoded.extAcmeIdentifierSet, 1);
ExpectIntEQ(decoded.extAcmeIdentifierCrit, 1);
ExpectIntEQ(decoded.acmeIdentifierSz, WC_SHA256_DIGEST_SIZE);
ExpectIntEQ(XMEMCMP(decoded.acmeIdentifier, expected,
WC_SHA256_DIGEST_SIZE), 0);

wc_FreeDecodedCert(&decoded);
if (keyInited) wc_ecc_free(&key);
if (rngInited) wc_FreeRng(&rng);
#endif
return EXPECT_RESULT();
} /* END test_wc_SetAcmeIdentifierExt */

/*
* Testing wc_SetKeyUsage()
*/
Expand Down Expand Up @@ -37017,6 +37101,7 @@ TEST_CASE testCases[] = {
#ifdef WOLFSSL_CERT_SIGN_CB
TEST_DECL(test_wc_SignCert_cb),
#endif
TEST_DECL(test_wc_SetAcmeIdentifierExt),
TEST_DECL(test_wc_SetKeyUsage),
TEST_DECL(test_wc_SetAuthKeyIdFromPublicKey_ex),
TEST_DECL(test_wc_SetSubjectBuffer),
Expand Down
114 changes: 114 additions & 0 deletions wolfcrypt/src/asn.c
Original file line number Diff line number Diff line change
Expand Up @@ -19014,6 +19014,39 @@ static int DecodeKeyUsageInternal(const byte* input, word32 sz,
return DecodeKeyUsage(input, sz, &cert->extKeyUsage);
}

#ifdef WOLFSSL_ACME_OID
/* Decodes the RFC 8737 id-pe-acmeIdentifier (1.3.6.1.5.5.7.1.31)
* extension value into cert->acmeIdentifier.
*
* The extnValue is an OCTET STRING wrapping a SHA-256 digest of the
* ACME keyAuth, per RFC 8737 3. Length is verified against
* WC_SHA256_DIGEST_SIZE.
*
* @param [in] input ASN.1 DER-encoded extension value.
* @param [in] sz Length of input in bytes.
* @param [in, out] cert DecodedCert to populate (acmeIdentifier and
* acmeIdentifierSz fields).
*
* @return 0 on success.
* @return ASN_PARSE_E when the inner OCTET STRING is missing or not
* exactly WC_SHA256_DIGEST_SIZE bytes.
*/
static int DecodeAcmeId(const byte* input, word32 sz, DecodedCert* cert)
{
word32 hashIdx = 0;
int hashLen = 0;

if (GetOctetString(input, &hashIdx, &hashLen, sz) < 0)
return ASN_PARSE_E;
if (hashLen != WC_SHA256_DIGEST_SIZE)
return ASN_PARSE_E;

XMEMCPY(cert->acmeIdentifier, &input[hashIdx], WC_SHA256_DIGEST_SIZE);
cert->acmeIdentifierSz = WC_SHA256_DIGEST_SIZE;
return 0;
}
#endif /* WOLFSSL_ACME_OID */

#ifdef WOLFSSL_ASN_TEMPLATE
/* ASN.1 template for KeyPurposeId.
* X.509: RFC 5280, 4.2.1.12 - Extended Key Usage.
Expand Down Expand Up @@ -20236,6 +20269,14 @@ int DecodeExtensionType(const byte* input, word32 length, word32 oid,
return ASN_PARSE_E;
break;
#endif /* WOLFSSL_DUAL_ALG_CERTS */
#ifdef WOLFSSL_ACME_OID
case ACME_IDENTIFIER_OID:
VERIFY_AND_SET_OID(cert->extAcmeIdentifierSet);
cert->extAcmeIdentifierCrit = critical ? 1 : 0;
if (DecodeAcmeId(&input[idx], length, cert) < 0)
return ASN_PARSE_E;
break;
#endif
default:
if (isUnknownExt != NULL)
*isUnknownExt = 1;
Expand Down Expand Up @@ -25250,6 +25291,9 @@ typedef struct DerCert {
#endif
byte certPolicies[MAX_CERTPOL_NB*MAX_CERTPOL_SZ]; /* Certificate Policies */
byte crlInfo[CTC_MAX_CRLINFO_SZ]; /* CRL Distribution Points */
#ifdef WOLFSSL_ACME_OID
byte acmeId[MAX_ACMEID_SZ]; /* RFC 8737 id-pe-acmeIdentifier */
#endif
#endif
#ifdef WOLFSSL_CERT_REQ
byte attrib[MAX_ATTRIB_SZ]; /* Cert req attributes encoded */
Expand Down Expand Up @@ -25280,6 +25324,9 @@ typedef struct DerCert {
#endif
int certPoliciesSz; /* encoded CertPolicies extension length*/
int crlInfoSz; /* encoded CRL Dist Points length */
#ifdef WOLFSSL_ACME_OID
int acmeIdSz; /* encoded acmeIdentifier length */
#endif
#endif
#ifdef WOLFSSL_ALT_NAMES
int altNamesSz; /* encoded AltNames extension length */
Expand Down Expand Up @@ -26510,6 +26557,12 @@ static const ASNItem static_certExtsASN[] = {
/* CRLINFO_SEQ */ { 0, ASN_SEQUENCE, 1, 1, 0 },
/* CRLINFO_OID */ { 1, ASN_OBJECT_ID, 0, 0, 0 },
/* CRLINFO_STR */ { 1, ASN_OCTET_STRING, 0, 0, 0 },
/* RFC 8737 id-pe-acmeIdentifier */
/* ACMEID_SEQ */ { 0, ASN_SEQUENCE, 1, 1, 0 },
/* ACMEID_OID */ { 1, ASN_OBJECT_ID, 0, 0, 0 },
/* ACMEID_CRIT */ { 1, ASN_BOOLEAN, 0, 0, 0 },
/* ACMEID_STR */ { 1, ASN_OCTET_STRING, 0, 1, 0 },
/* ACMEID_HASH */ { 2, ASN_OCTET_STRING, 0, 0, 0 },
#ifdef WOLFSSL_DUAL_ALG_CERTS
/* SAPKI_SEQ */ { 0, ASN_SEQUENCE, 1, 1, 0 },
/* SAPKI_OID */ { 1, ASN_OBJECT_ID, 0, 0, 0 },
Expand Down Expand Up @@ -26568,6 +26621,11 @@ enum {
CERTEXTSASN_IDX_CRLINFO_SEQ,
CERTEXTSASN_IDX_CRLINFO_OID,
CERTEXTSASN_IDX_CRLINFO_STR,
CERTEXTSASN_IDX_ACMEID_SEQ,
CERTEXTSASN_IDX_ACMEID_OID,
CERTEXTSASN_IDX_ACMEID_CRIT,
CERTEXTSASN_IDX_ACMEID_STR,
CERTEXTSASN_IDX_ACMEID_HASH,
#ifdef WOLFSSL_DUAL_ALG_CERTS
CERTEXTSASN_IDX_SAPKI_SEQ,
CERTEXTSASN_IDX_SAPKI_OID,
Expand Down Expand Up @@ -26623,6 +26681,10 @@ static int EncodeExtensions(Cert* cert, byte* output, word32 maxSz,
static const byte nsCertOID[] = { 0x60, 0x86, 0x48, 0x01,
0x86, 0xF8, 0x42, 0x01, 0x01 };
static const byte crlInfoOID[] = { 0x55, 0x1D, 0x1F };
#ifdef WOLFSSL_ACME_OID
static const byte acmeIdOID[] = { 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07,
0x01, 0x1F };
#endif
#ifdef WOLFSSL_DUAL_ALG_CERTS
static const byte sapkiOID[] = { 0x55, 0x1d, 0x48 };
static const byte altSigAlgOID[] = { 0x55, 0x1d, 0x49 };
Expand Down Expand Up @@ -26878,6 +26940,24 @@ static int EncodeExtensions(Cert* cert, byte* output, word32 maxSz,
CERTEXTSASN_IDX_CRLINFO_STR);
}

#ifdef WOLFSSL_ACME_OID
/* id-pe-acmeIdentifier (TLS-ALPN-01 challenge cert).
* Always critical=TRUE. */
if (cert->acmeIdentifierSz == WC_SHA256_DIGEST_SIZE) {
SetASN_Buffer(&dataASN[CERTEXTSASN_IDX_ACMEID_OID],
acmeIdOID, sizeof(acmeIdOID));
SetASN_Boolean(&dataASN[CERTEXTSASN_IDX_ACMEID_CRIT], 1);
SetASN_Buffer(&dataASN[CERTEXTSASN_IDX_ACMEID_HASH],
cert->acmeIdentifier, (word32)cert->acmeIdentifierSz);
}
else
#endif /* WOLFSSL_ACME_OID */
{
/* Don't write out the ACME identifier extension. */
SetASNItem_NoOut(dataASN, CERTEXTSASN_IDX_ACMEID_SEQ,
CERTEXTSASN_IDX_ACMEID_HASH);
}

#ifdef WOLFSSL_DUAL_ALG_CERTS
if (cert->sapkiDer != NULL) {
/* Set subject alternative public key info OID, criticality and
Expand Down Expand Up @@ -29313,6 +29393,40 @@ int wc_SetExtKeyUsage(Cert *cert, const char *value)
return ret;
}

#ifdef WOLFSSL_ACME_OID
/* Set the id-pe-acmeIdentifier extension value from the ACME
* keyAuth string. Computes SHA-256 over keyAuth and stores the digest
* as the extension value. RFC 8737 3 requires critical=TRUE; that's
* applied at encode time in EncodeExtensions.
*
* keyAuth is the raw bytes of the key authorization string per
* RFC 8555 8.1: token "." JWK_thumbprint.
*/
int wc_SetAcmeIdentifierExt(Cert *cert, const byte *keyAuth, word32 keyAuthSz)
{
int ret;
byte digest[WC_SHA256_DIGEST_SIZE];
wc_Sha256 sha;

if (cert == NULL || keyAuth == NULL || keyAuthSz == 0)
return BAD_FUNC_ARG;

ret = wc_InitSha256(&sha);
if (ret != 0)
return ret;
ret = wc_Sha256Update(&sha, keyAuth, keyAuthSz);
if (ret == 0)
ret = wc_Sha256Final(&sha, digest);
wc_Sha256Free(&sha);
if (ret != 0)
return ret;

XMEMCPY(cert->acmeIdentifier, digest, WC_SHA256_DIGEST_SIZE);
cert->acmeIdentifierSz = WC_SHA256_DIGEST_SIZE;
return 0;
}
#endif /* WOLFSSL_ACME_OID */

#ifdef WOLFSSL_EKU_OID
/*
* cert structure to set EKU oid in
Expand Down
52 changes: 52 additions & 0 deletions wolfcrypt/src/asn_orig.c
Original file line number Diff line number Diff line change
Expand Up @@ -5295,6 +5295,31 @@ static int SetAKID(byte* output, word32 outSz, byte *input, word32 length,
return (int)idx + enc_valSz;
}

#ifdef WOLFSSL_ACME_OID
/* encode RFC 8737 id-pe-acmeIdentifier extension, return total bytes written
* RFC8737 : critical */
static int SetAcmeIdentifier(byte* output, word32 outSz, const byte* digest,
word32 digestSz)
{
byte inner[1 + MAX_LENGTH_SZ + WC_SHA256_DIGEST_SIZE];
word32 innerSz;
const byte acmeId_oid[] = { 0x06, 0x08, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07,
0x01, 0x1F, 0x01, 0x01, 0xFF, 0x04 };

if (output == NULL || digest == NULL)
return BAD_FUNC_ARG;
if (digestSz != WC_SHA256_DIGEST_SIZE)
return BAD_FUNC_ARG;

innerSz = SetOctetString(digestSz, inner);
XMEMCPY(inner + innerSz, digest, digestSz);
innerSz += digestSz;

return SetOidValue(output, outSz, acmeId_oid, sizeof(acmeId_oid),
inner, innerSz);
}
#endif /* WOLFSSL_ACME_OID */

/* encode Key Usage, return total bytes written
* RFC5280 : critical */
static int SetKeyUsage(byte* output, word32 outSz, word16 input)
Expand Down Expand Up @@ -6340,6 +6365,22 @@ static int EncodeCert(Cert* cert, DerCert* der, RsaKey* rsaKey, ecc_key* eccKey,
der->certPoliciesSz = 0;
#endif /* WOLFSSL_CERT_EXT */

#ifdef WOLFSSL_ACME_OID
/* RFC 8737 id-pe-acmeIdentifier (TLS-ALPN-01 challenge cert).
* Always critical=TRUE. */
if (cert->acmeIdentifierSz == WC_SHA256_DIGEST_SIZE) {
der->acmeIdSz = SetAcmeIdentifier(der->acmeId, sizeof(der->acmeId),
cert->acmeIdentifier,
(word32)cert->acmeIdentifierSz);
if (der->acmeIdSz <= 0)
return EXTENSIONS_E;

der->extensionsSz += der->acmeIdSz;
}
else
der->acmeIdSz = 0;
#endif

/* put extensions */
if (der->extensionsSz > 0) {

Expand Down Expand Up @@ -6436,6 +6477,17 @@ static int EncodeCert(Cert* cert, DerCert* der, RsaKey* rsaKey, ecc_key* eccKey,
return EXTENSIONS_E;
}
#endif /* WOLFSSL_CERT_EXT */

#ifdef WOLFSSL_ACME_OID
/* put ACME Identifier */
if (der->acmeIdSz) {
ret = SetExtensions(der->extensions, sizeof(der->extensions),
&der->extensionsSz,
der->acmeId, der->acmeIdSz);
if (ret <= 0)
return EXTENSIONS_E;
}
#endif
}

der->total = der->versionSz + der->serialSz + der->sigAlgoSz +
Expand Down
Loading
Loading