Skip to content
Open
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
108 changes: 101 additions & 7 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 @@ -130,14 +131,42 @@ struct WOLFSSHD_AUTH {
#endif

#ifndef MAX_LINE_SZ
/* Sized to hold the largest authorized_keys entry. */
/* sized for the largest authorized_keys entry, composite pubkeys
* included */
#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)
/* x509v3-ssh-mldsa-87: ML-DSA-87 pubkey + CA sig + DER
* overhead, base64-encoded. COMPOSITE_MAX_TRAD_PUB_SZ is
* headroom for a future composite x509v3 variant. */
#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 @@ -240,9 +269,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 @@ -259,7 +304,8 @@ static int CheckAuthKeysLine(char* line, word32 lineSz, const byte* key,
}
}
if (ret == WSSHD_AUTH_SUCCESS) {
for (i = 0; i < NUM_ALLOWED_TYPES; ++i) {
for (i = 0; i < (int)(sizeof(allowedTypes) / sizeof(allowedTypes[0]));
++i) {
if (WSTRCMP(type, allowedTypes[i]) == 0) {
typeOk = 1;
break;
Expand Down Expand Up @@ -894,6 +940,54 @@ int wolfSSHD_OpenSecureFile(const char* path, WUID_T ownerUid,
#endif
}

/* detects OpenSSH vs ASN1/DER format of a raw host private key buffer;
* privBuf/privBufSz are set to the buffer to actually load (data, or der's
* buffer if PEM decoded); returns WOLFSSH_FORMAT_ASN1/WOLFSSH_FORMAT_OPENSSH,
* or negative on error */
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;

/* wstrnstr() halts at the first embedded NUL, so for a raw binary
* "openssh-key-v1\0..." buffer this bails out after 15 bytes instead
* of scanning binary key material; falls through to the WMEMCMP
* magic check below. */
if (WSTRNSTR((const char*)*privBuf,
"-----BEGIN OPENSSH PRIVATE KEY-----", *privBufSz) != NULL) {
keyFormat = WOLFSSH_FORMAT_OPENSSH;
}
else if (*privBufSz >= sizeof("openssh-key-v1") &&
WMEMCMP(*privBuf, "openssh-key-v1",
sizeof("openssh-key-v1")) == 0) {
/* sizeof() includes the magic's trailing NUL */
keyFormat = WOLFSSH_FORMAT_OPENSSH;
}
}
else {
*privBuf = (*der)->buffer;
*privBufSz = (*der)->length;
/* PEM-decoded result may still be an OpenSSH binary blob */
if (*privBufSz >= sizeof("openssh-key-v1") &&
WMEMCMP(*privBuf, "openssh-key-v1",
sizeof("openssh-key-v1")) == 0) {
keyFormat = WOLFSSH_FORMAT_OPENSSH;
}
}

return keyFormat;
}

WOLFSSHD_STATIC int SearchForPubKey(const char* path,
const char* authKeysFile, const char* user,
const WS_UserAuthData_PublicKey* pubKeyCtx,
Expand Down
6 changes: 6 additions & 0 deletions apps/wolfsshd/auth.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
#define WOLFSSH_USER_GET_STRING(x) #x
#define WOLFSSH_USER_STRING(x) WOLFSSH_USER_GET_STRING(x)

#include <wolfssl/wolfcrypt/asn_public.h> /* for DerBuffer */

#if 0

typedef struct USER_NODE USER_NODE;
Expand Down Expand Up @@ -93,6 +95,10 @@ 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);

/* classifies a loaded host private key buffer as OpenSSH or ASN1/DER */
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