Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ keys/*-ossh-*cert.pub
random-test.txt
random-test-result.txt
test.dat
# Scratch file the api tests write in the working directory. Removed on a
# clean run, left behind when one aborts.
ossh-cert-line.tmp

# test output
tests/*.test
Expand Down
1 change: 1 addition & 0 deletions keys/include.am
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ EXTRA_DIST+= \
keys/pubkeys-rsa.txt keys/passwd.txt keys/ca-cert-ecc.der \
keys/ca-cert-ecc.pem keys/ca-key-ecc.der keys/ca-key-ecc.pem \
keys/server-cert.der keys/server-cert.pem \
keys/server-cert-ed25519.der keys/server-cert-ed25519.pem \
keys/fred-cert.der keys/fred-cert.pem \
keys/server-key.pem keys/fred-key.der keys/fred-key.pem \
keys/id_ecdsa keys/id_ecdsa.pub keys/id_rsa keys/id_rsa.pub \
Expand Down
10 changes: 10 additions & 0 deletions keys/renewcerts.sh
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,16 @@ openssl req -subj '/C=US/ST=Washington/L=Seattle/O=Eliptic/OU=ECC/CN=www.wolfssl
openssl x509 -req -in server-cert.csr -days 3650 -extfile "$CONFIG" -extensions v3_server -CA ca-cert-ecc.pem -CAkey ca-key-ecc.pem -text -out server-cert.pem -set_serial 8
openssl x509 -in server-cert.pem -outform DER -out server-cert.der

# renew server-cert-ed25519. Ed25519 has no x509v3-* SSH algorithm name, so
# this certificate exercises the rejection of an unmappable key type. Its key
# is not a host key, so it is dropped once the certificate is signed.
openssl genpkey -algorithm ed25519 -out server-cert-ed25519-key.pem
openssl req -subj '/C=US/ST=Washington/L=Seattle/O=Eliptic/OU=Ed25519/CN=www.wolfssl.com/emailAddress=server@example.com' -key server-cert-ed25519-key.pem -out server-cert-ed25519.csr -config "$CONFIG" -new -nodes

openssl x509 -req -in server-cert-ed25519.csr -days 3650 -extfile "$CONFIG" -extensions v3_server -CA ca-cert-ecc.pem -CAkey ca-key-ecc.pem -text -out server-cert-ed25519.pem -set_serial 9
openssl x509 -in server-cert-ed25519.pem -outform DER -out server-cert-ed25519.der
rm -f server-cert-ed25519-key.pem server-cert-ed25519.csr

rm index.*
if [ -n "$1" ]; then
rm -f "$CONFIG"
Expand Down
Binary file added keys/server-cert-ed25519.der
Binary file not shown.
50 changes: 50 additions & 0 deletions keys/server-cert-ed25519.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 9 (0x9)
Signature Algorithm: ecdsa-with-SHA256
Issuer: C=US, ST=Washington, L=Seattle, O=wolfSSL, OU=Development, CN=www.wolfssl.com, emailAddress=ca@example.com
Validity
Not Before: Aug 3 05:11:17 2026 GMT
Not After : Jul 31 05:11:17 2036 GMT
Subject: C=US, ST=Washington, L=Seattle, O=Eliptic, OU=Ed25519, CN=www.wolfssl.com, emailAddress=server@example.com
Subject Public Key Info:
Public Key Algorithm: ED25519
ED25519 Public-Key:
pub:
69:97:cf:00:fe:3c:27:d0:1b:3f:14:60:5a:b9:68:
a1:8c:89:64:93:ee:89:8c:48:31:a1:05:b1:f6:77:
bb:57
X509v3 extensions:
X509v3 Subject Key Identifier:
F7:D0:2B:CD:7D:A0:B7:1B:90:EB:F3:E8:E6:D0:A5:E9:C7:5F:E6:72
X509v3 Authority Key Identifier:
keyid:56:8E:9A:C3:F0:42:DE:18:B9:45:55:6E:F9:93:CF:EA:C3:F3:A5:21
DirName:/C=US/ST=Washington/L=Seattle/O=wolfSSL/OU=Development/CN=www.wolfssl.com/emailAddress=ca@example.com
serial:06
X509v3 Subject Alternative Name:
DNS:example, IP Address:127.0.0.1
Signature Algorithm: ecdsa-with-SHA256
Signature Value:
30:44:02:20:58:41:57:d7:27:fd:e0:a6:25:bf:40:11:31:5a:
e1:6d:7c:60:35:dc:04:f9:6e:2e:8c:d5:4b:41:1d:65:d8:16:
02:20:36:9c:e1:fa:4d:e1:aa:1f:19:4e:41:99:4d:79:ee:ed:
fb:7c:68:7e:0a:48:c6:12:7d:44:12:be:59:55:d3:6f
-----BEGIN CERTIFICATE-----
MIIC7jCCApWgAwIBAgIBCTAKBggqhkjOPQQDAjCBlTELMAkGA1UEBhMCVVMxEzAR
BgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUxEDAOBgNVBAoMB3dv
bGZTU0wxFDASBgNVBAsMC0RldmVsb3BtZW50MRgwFgYDVQQDDA93d3cud29sZnNz
bC5jb20xHTAbBgkqhkiG9w0BCQEWDmNhQGV4YW1wbGUuY29tMB4XDTI2MDgwMzA1
MTExN1oXDTM2MDczMTA1MTExN1owgZUxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApX
YXNoaW5ndG9uMRAwDgYDVQQHDAdTZWF0dGxlMRAwDgYDVQQKDAdFbGlwdGljMRAw
DgYDVQQLDAdFZDI1NTE5MRgwFgYDVQQDDA93d3cud29sZnNzbC5jb20xITAfBgkq
hkiG9w0BCQEWEnNlcnZlckBleGFtcGxlLmNvbTAqMAUGAytlcAMhAGmXzwD+PCfQ
Gz8UYFq5aKGMiWST7omMSDGhBbH2d7tXo4IBATCB/jAdBgNVHQ4EFgQU99ArzX2g
txuQ6/Po5tCl6cdf5nIwgcIGA1UdIwSBujCBt4AUVo6aw/BC3hi5RVVu+ZPP6sPz
pSGhgZukgZgwgZUxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApXYXNoaW5ndG9uMRAw
DgYDVQQHDAdTZWF0dGxlMRAwDgYDVQQKDAd3b2xmU1NMMRQwEgYDVQQLDAtEZXZl
bG9wbWVudDEYMBYGA1UEAwwPd3d3LndvbGZzc2wuY29tMR0wGwYJKoZIhvcNAQkB
Fg5jYUBleGFtcGxlLmNvbYIBBjAYBgNVHREEETAPggdleGFtcGxlhwR/AAABMAoG
CCqGSM49BAMCA0cAMEQCIFhBV9cn/eCmJb9AETFa4W18YDXcBPluLozVS0EdZdgW
AiA2nOH6TeGqHxlOQZlNee7t+3xofgpIxhJ9RBK+WVXTbw==
-----END CERTIFICATE-----
87 changes: 58 additions & 29 deletions src/internal.c
Original file line number Diff line number Diff line change
Expand Up @@ -1951,13 +1951,9 @@ int IdentifyAsn1Key(const byte* in, word32 inSz, int isPrivate, void* heap,
ret = wc_MlDsaKey_PublicKeyDecode(&key->ks.mldsa.key,
in, inSz, &idx);
if (ret != 0) {
/* Length-only fallback for local key/cert loading
* (wolfSSH_ReadKey_buffer_ex / IdentifyCert) when SPKI
* OID decode fails: wc_MlDsaKey_ImportPubRaw accepts an
* ML-DSA blob of exactly 1312/1952/2592 bytes and tags
* it ID_MLDSA44/65/87. Not used on the remote user-auth
* path; do not wire this probe into remote auth assuming
* it cryptographically validates the key. */
/* Local loading only: size alone tags a raw ML-DSA
* blob when SPKI OID decode fails. This does not
* validate the key, so keep it off remote auth. */
struct { byte level; byte id; } kProbe[3];
word32 nProbe = 0, li;
#ifndef WOLFSSH_NO_MLDSA44
Expand Down Expand Up @@ -2076,17 +2072,10 @@ int IdentifyAsn1Key(const byte* in, word32 inSz, int isPrivate, void* heap,


#ifdef WOLFSSH_CERTS
/*
* Identifies the flavor of an X.509 certificate, RSA, ML-DSA or ECDSA, returns
* the key type ID. The process is to decode the certificate and pass the
* public key to IdentifyAsn1Key.
*
* @param in certificate to identify
* @param inSz size of certificate
* @param heap heap to use for memory allocation
* @return keyId as int, WS_MEMORY_E, WS_UNIMPLEMENTED_E
*/
static int IdentifyCert(const byte* in, word32 inSz, void* heap)
/* Identifies the key held inside an X.509 certificate, returning its plain
key type ID or a WS_ error. See IdentifyCert() for the x509v3-* algorithm
ID sent on the wire. */
static int IdentifyCertKey(const byte* in, word32 inSz, void* heap)
{
struct DecodedCert* cert = NULL;
#ifndef WOLFSSH_SMALL_STACK
Expand All @@ -2106,13 +2095,22 @@ static int IdentifyCert(const byte* in, word32 inSz, void* heap)
}
#endif

/* Each wolfSSL result below is mapped where it is produced, so this
function returns only a key ID or a WS_ code. */
if (ret == 0) {
wc_InitDecodedCert(cert, in, inSz, heap);
ret = wc_ParseCert(cert, CERT_TYPE, 0, NULL);
if (ret != 0) {
ret = WS_PARSE_E;
}
}
if (ret == 0) {
/* Asking with no buffer answers with the length and LENGTH_ONLY_E. */
ret = wc_GetPubKeyDerFromCert(cert, NULL, &keySz);
if (ret == LENGTH_ONLY_E) {
if (ret != LENGTH_ONLY_E) {
ret = WS_PARSE_E;
}
else {
ret = 0;
key = (byte*)WMALLOC(keySz, heap, DYNTYPE_PUBKEY);
if (key == NULL) {
Expand All @@ -2123,6 +2121,9 @@ static int IdentifyCert(const byte* in, word32 inSz, void* heap)

if (ret == 0) {
ret = wc_GetPubKeyDerFromCert(cert, key, &keySz);
if (ret != 0) {
ret = WS_PARSE_E;
}
}

if (ret == 0) {
Expand Down Expand Up @@ -2233,6 +2234,31 @@ static INLINE byte CertTypeForId(byte id)
return id;
}


/* Identifies an X.509 certificate, returning the x509v3-* algorithm ID sent
on the wire. A key type with no x509v3 name in this build is rejected
rather than reported under its plain key name. */
int IdentifyCert(const byte* in, word32 inSz, void* heap)
{
byte certId;
int ret;

ret = IdentifyCertKey(in, inSz, heap);

if (ret >= 0) {
certId = CertTypeForId((byte)ret);
if (certId == (byte)ret) {
WLOG(WS_LOG_DEBUG, "No x509v3 algorithm for this certificate");
ret = WS_INVALID_ALGO_ID;
}
else {
ret = (int)certId;
}
}

return ret;
}

#define HINTISSET(x) ((x) != WOLFSSH_MAX_PVT_KEYS)

static int UpdateHostCertificates(WOLFSSH_CTX* ctx,
Expand Down Expand Up @@ -2326,18 +2352,14 @@ static int UpdateHostCertificates(WOLFSSH_CTX* ctx,
}

static int SetHostCertificate(WOLFSSH_CTX* ctx,
byte keyId, byte* der, word32 derSz, int dynamicType)
byte certId, byte* der, word32 derSz, int dynamicType)
{
/*
* The keyId is for the key inside the certificate. wolfSSH_ProcessBuffer
* will decode the certificate, get the public key inside, and identify
* that. keyId will be: ssh-rsa, ecdsa-sha2-nistp256, etc.
*/
/* The certId is the x509v3-* algorithm the certificate is presented as,
* identified by wolfSSH_ProcessBuffer before calling here. */

word32 destIdx,
certIdx = WOLFSSH_MAX_PVT_KEYS, keyIdx = WOLFSSH_MAX_PVT_KEYS;
int ret = WS_SUCCESS;
byte certId = CertTypeForId(keyId);

/* Look for the specified certId. Add it if not present,
* replace it if present. Call UpdateHostCertificate().
Expand All @@ -2347,7 +2369,10 @@ static int SetHostCertificate(WOLFSSH_CTX* ctx,
if (ctx->privateKey[destIdx].publicKeyFmt == certId) {
certIdx = destIdx;
}
if (ctx->privateKey[destIdx].publicKeyFmt == keyId) {
/* The key for this certificate sits in the slot whose plain
algorithm maps onto certId. */
else if (CertTypeForId(ctx->privateKey[destIdx].publicKeyFmt)
== certId) {
keyIdx = destIdx;
}
}
Expand Down Expand Up @@ -2618,12 +2643,16 @@ int wolfSSH_ProcessBuffer(WOLFSSH_CTX* ctx,
WFREE(der, heap, dynamicType);
return ret;
}
keyId = (byte)ret;
ret = SetHostCertificate(ctx, keyId, der, derSz, dynamicType);
ret = SetHostCertificate(ctx, (byte)ret, der, derSz, dynamicType);
}
else if (type == BUFTYPE_CA) {
if (ctx->certMan != NULL) {
ret = wolfSSH_CERTMAN_LoadRootCA_buffer(ctx->certMan, der, derSz);
/* That call answers in wolfSSL codes apart from these two, so
anything else becomes one of ours. */
if (ret != WS_SUCCESS && ret != WS_BAD_ARGUMENT) {
ret = WS_PARSE_E;
}
}
else {
WLOG(WS_LOG_DEBUG, "Error no cert manager set");
Expand Down
Loading
Loading