Skip to content
Draft
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
119 changes: 111 additions & 8 deletions apps/wolfsshd/auth.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
#include <wolfssl/wolfcrypt/wc_port.h>
#include <wolfssl/wolfcrypt/error-crypt.h>
#include <wolfssl/wolfcrypt/coding.h>
#include <wolfssl/wolfcrypt/asn_public.h>

#ifdef WOLFSSL_FPKI
#include <wolfssl/wolfcrypt/asn.h>
Expand Down Expand Up @@ -118,14 +119,43 @@ struct WOLFSSHD_AUTH {
#endif

#ifndef MAX_LINE_SZ
/* Sized to hold the largest authorized_keys entry. */
/* Sized to hold the largest authorized_keys entry. Composite
* (ML-DSA + traditional) entries carry an extra COMPOSITE_MAX_TRAD_PUB_SZ
* bytes of traditional public key on top of the plain ML-DSA pubkey. */
#ifndef WOLFSSH_NO_MLDSA
#ifndef WOLFSSH_NO_MLDSA87
#define MAX_LINE_SZ ((WC_MLDSA_87_PUB_KEY_SIZE + 2) / 3 * 4 + 640)
#if defined(WOLFSSH_CERTS)
/* An x509v3-ssh-mldsa-87 entry carries a full certificate:
* the ML-DSA-87 public key plus a CA's ML-DSA-87 signature
* plus DER overhead, all base64-encoded. */
#define MAX_LINE_SZ \
((WC_MLDSA_87_PUB_KEY_SIZE + WC_MLDSA_87_SIG_SIZE + \
COMPOSITE_MAX_TRAD_PUB_SZ + 1024 + 2) / 3 * 4 + 640)
#else
#define MAX_LINE_SZ \
((WC_MLDSA_87_PUB_KEY_SIZE + COMPOSITE_MAX_TRAD_PUB_SZ + \
2) / 3 * 4 + 640)
#endif
#elif !defined(WOLFSSH_NO_MLDSA65)
#define MAX_LINE_SZ ((WC_MLDSA_65_PUB_KEY_SIZE + 2) / 3 * 4 + 640)
#if defined(WOLFSSH_CERTS)
#define MAX_LINE_SZ \
((WC_MLDSA_65_PUB_KEY_SIZE + WC_MLDSA_65_SIG_SIZE + \
COMPOSITE_MAX_TRAD_PUB_SZ + 1024 + 2) / 3 * 4 + 640)
#else
#define MAX_LINE_SZ \
((WC_MLDSA_65_PUB_KEY_SIZE + COMPOSITE_MAX_TRAD_PUB_SZ + \
2) / 3 * 4 + 640)
#endif
#else
#define MAX_LINE_SZ ((WC_MLDSA_44_PUB_KEY_SIZE + 2) / 3 * 4 + 640)
#if defined(WOLFSSH_CERTS)
#define MAX_LINE_SZ \
((WC_MLDSA_44_PUB_KEY_SIZE + WC_MLDSA_44_SIG_SIZE + \
COMPOSITE_MAX_TRAD_PUB_SZ + 1024 + 2) / 3 * 4 + 640)
#else
#define MAX_LINE_SZ \
((WC_MLDSA_44_PUB_KEY_SIZE + COMPOSITE_MAX_TRAD_PUB_SZ + \
2) / 3 * 4 + 640)
#endif
#endif
#else
#define MAX_LINE_SZ 900
Expand Down Expand Up @@ -231,9 +261,25 @@ static int CheckAuthKeysLine(char* line, word32 lineSz, const byte* key,
#endif
#endif
#endif
#if !defined(WOLFSSH_NO_MLDSA44) && !defined(WOLFSSH_NO_ECDSA)
"ssh-mldsa44-es256",
#endif
#if !defined(WOLFSSH_NO_MLDSA65) && !defined(WOLFSSH_NO_ECDSA)
"ssh-mldsa65-es256",
#endif
#if !defined(WOLFSSH_NO_MLDSA87) && !defined(WOLFSSH_NO_ECDSA)
"ssh-mldsa87-es384",
#endif
#if !defined(WOLFSSH_NO_MLDSA44) && !defined(WOLFSSH_NO_ED25519)
"ssh-mldsa44-ed25519@openssh.com",
#endif
#if !defined(WOLFSSH_NO_MLDSA65) && !defined(WOLFSSH_NO_ED25519)
"ssh-mldsa65-ed25519",
#endif
#if !defined(WOLFSSH_NO_MLDSA87) && defined(HAVE_ED448)
"ssh-mldsa87-ed448",
#endif
};
const int NUM_ALLOWED_TYPES =
(int)(sizeof(allowedTypes) / sizeof(allowedTypes[0]));
int typeOk = 0;
int i;

Expand All @@ -250,8 +296,9 @@ static int CheckAuthKeysLine(char* line, word32 lineSz, const byte* key,
}
}
if (ret == WSSHD_AUTH_SUCCESS) {
for (i = 0; i < NUM_ALLOWED_TYPES; ++i) {
if (WSTRCMP(type, allowedTypes[i]) == 0) {
for (i = 0; i < (int)(sizeof(allowedTypes) / sizeof(allowedTypes[0]));
++i) {
if (allowedTypes[i] != NULL && WSTRCMP(type, allowedTypes[i]) == 0) {
typeOk = 1;
break;
}
Expand Down Expand Up @@ -783,6 +830,62 @@ int wolfSSHD_OpenSecureFile(const char* path, WUID_T ownerUid,
#endif
}

/* Determine the wolfSSH_CTX_UsePrivateKey_buffer() format of a raw host
* private key buffer, and hand back the buffer/length to actually load.
*
* PEM-armored OpenSSH keys (BEGIN OPENSSH PRIVATE KEY) and raw binary
* openssh-key-v1 blobs are both loaded with WOLFSSH_FORMAT_OPENSSH; anything
* else (including a successfully PEM-decoded traditional key, which starts
* with a DER SEQUENCE tag) is loaded as WOLFSSH_FORMAT_ASN1.
*
* data - raw file contents (may be PEM or DER/OpenSSH binary).
* dataSz - size of data.
* der - scratch DerBuffer used when data is PEM; caller must
* wc_FreeDer() it after use.
* privBuf - set to the buffer to actually load (either data, or der's
* buffer if PEM decoding succeeded).
* privBufSz - set to the size of *privBuf.
*
* Returns WOLFSSH_FORMAT_ASN1 or WOLFSSH_FORMAT_OPENSSH. */
int wolfSSHD_DetectPrivKeyFormat(byte* data, word32 dataSz, DerBuffer** der,
byte** privBuf, word32* privBufSz)
{
int keyFormat = WOLFSSH_FORMAT_ASN1;

if (data == NULL || dataSz == 0 || der == NULL || privBuf == NULL ||
privBufSz == NULL) {
return WS_BAD_ARGUMENT;
}

if (wc_PemToDer(data, dataSz, PRIVATEKEY_TYPE, der, NULL, NULL, NULL)
!= 0) {
*privBuf = data;
*privBufSz = dataSz;

if (WSTRNSTR((const char*)*privBuf,
"-----BEGIN OPENSSH PRIVATE KEY-----", *privBufSz) != NULL) {
keyFormat = WOLFSSH_FORMAT_OPENSSH;
}
else if (*privBufSz >= 15 &&
WMEMCMP(*privBuf, "openssh-key-v1", 15) == 0) {
/* Compare 15 bytes: the magic includes a NUL. */
keyFormat = WOLFSSH_FORMAT_OPENSSH;
}
}
else {
*privBuf = (*der)->buffer;
*privBufSz = (*der)->length;
/* wc_PemToDer decoded the PEM armor; if the result is an OpenSSH
* binary blob, select the matching format. */
if (*privBufSz >= 15 &&
WMEMCMP(*privBuf, "openssh-key-v1", 15) == 0) {
keyFormat = WOLFSSH_FORMAT_OPENSSH;
}
}

return keyFormat;
}

static int SearchForPubKey(const char* path, const char* authKeysFile,
const WS_UserAuthData_PublicKey* pubKeyCtx,
WUID_T uid, int strictModes)
Expand Down
8 changes: 8 additions & 0 deletions apps/wolfsshd/auth.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
#ifndef WOLFAUTH_H
#define WOLFAUTH_H

#include <wolfssl/wolfcrypt/asn_public.h> /* DerBuffer, used by
* wolfSSHD_DetectPrivKeyFormat() */

#if 0
typedef struct USER_NODE USER_NODE;

Expand Down Expand Up @@ -86,6 +89,11 @@ int wolfSSHD_GetHomeDirectory(WOLFSSHD_AUTH* auth, WOLFSSH* ssh, WCHAR* out, int
int wolfSSHD_OpenSecureFile(const char* path, WUID_T ownerUid,
int rejectReadable, void* heap, WFILE** out);

/* Shared by wolfsshd.c's SetupCTX() to classify a loaded host private key
* buffer as OpenSSH or ASN1/DER. See the definition in auth.c. */
int wolfSSHD_DetectPrivKeyFormat(byte* data, word32 dataSz, DerBuffer** der,
byte** privBuf, word32* privBufSz);

#ifdef WOLFSSHD_UNIT_TEST
#ifndef _WIN32
extern int (*wsshd_setregid_cb)(WGID_T, WGID_T);
Expand Down
Loading
Loading