/* SPDX-License-Identifier: GPL-3.0-only * Extracted wolfSSH functions retain upstream GPL notices in generated source. * Crypto doubles test parser gating, not cryptographic validity. */ #include #include #include #include #include #include #include typedef uint8_t byte; typedef uint32_t word32; #define WS_SUCCESS 0 #define WS_BUFFER_E -1 #define WS_BAD_ARGUMENT -2 #define WS_INVALID_CHANID -3 #define WS_OVERFLOW_E -4 #define WS_MEMORY_E -5 #define WS_INVALID_ALGO_ID -6 #define WS_CRYPTO_FAILED -7 #define WS_ECC_E -8 #define WS_ED25519_E -9 #define WS_INVALID_STATE_E -10 #define WS_CHANOPEN_FAILED -11 #define MSGID_USERAUTH_REQUEST 50 #define MSG_ID_SZ 1 #define BOOLEAN_SZ 1 #define Ed25519 0 #define UINT32_SZ 4 #define WOLFSSH_MAX_NAMESZ 32 #define CLIENT_USERAUTH_REQUEST_DONE 42 #define WS_CHANNEL_ID_SELF 0 #define WLOG(...) ((void)0) #define WOLFSSH_UNUSED(x) ((void)(x)) #define WMEMCPY memcpy #define WMEMCMP memcmp #define WMALLOC(n,h,t) malloc(n) #define WFREE(p,h,t) free(p) #define ECDSA_ASN_SIG_SZ 80 #define INVALID_DEVID -1 #define WC_SIGNATURE_TYPE_ECC 1 struct context { void *heap; }; typedef struct { struct context *ctx; int clientState; const byte *sessionId; word32 sessionIdSz; } WOLFSSH; typedef struct { word32 peerWindowSz; } WOLFSSH_CHANNEL; typedef struct { const byte *publicKey, *publicKeyType, *signature; word32 publicKeySz, publicKeyTypeSz, signatureSz; const byte *dataToSign; } WS_UserAuthData_PublicKey; typedef struct { word32 usernameSz, serviceNameSz, authNameSz; } WS_UserAuthData; typedef struct { int unused; } ed25519_key; typedef struct { int unused; } ecc_key; enum wc_HashType { HASH_SHA256 }; static unsigned imports, converts, verifies, finds, cases; static unsigned ed_imports, ed_starts, ed_updates, ed_finals; static const byte *expected_r, *expected_s, *expected_ed_sig; static word32 expected_r_sz, expected_s_sz, expected_ed_sig_sz; static byte ed_message[512]; static word32 ed_message_sz; static int verify_failure; static uintptr_t nested_begin, nested_end, nested_outer_end; static WOLFSSH_CHANNEL channel; static WOLFSSH_CHANNEL *ChannelFind(WOLFSSH *ssh, word32 id, int side) { finds++; return id == 7 ? &channel : NULL; } static void ato32(const byte *p, word32 *v) { uintptr_t address=(uintptr_t)p; if (nested_begin != 0 && address>=nested_begin && address>24; p[1]=v>>16; p[2]=v>>8; p[3]=v; } static int wc_ecc_init_ex(ecc_key *k, void *h, int id) { return 0; } static int wc_ecc_import_x963(const byte *p, word32 n, ecc_key *k) { imports++; return 0; } static void wc_ecc_free(ecc_key *k) {} static int wc_ecc_rs_raw_to_sig(const byte *r, word32 rn, const byte *s, word32 sn, byte *out, word32 *n) { converts++; if (expected_r != NULL) { assert(rn==expected_r_sz && sn==expected_s_sz); assert(memcmp(r,expected_r,rn)==0 && memcmp(s,expected_s,sn)==0); } return 0; } static int wc_SignatureVerifyHash(enum wc_HashType h, int t, byte *d, word32 dn, byte *s, word32 sn, ecc_key *k, size_t kn) { verifies++; return verify_failure; } static void c32toa(word32 v, byte *p) { put(p,v); } static int wc_ed25519_init_ex(ed25519_key *key, void *heap, int id) { return 0; } static void wc_ed25519_free(ed25519_key *key) {} static int wc_ed25519_import_public(const byte *p, word32 n, ed25519_key *key) { ed_imports++; assert(n==32); return 0; } static int wc_ed25519_verify_msg_init(const byte *sig, word32 n, ed25519_key *key, byte type, const byte *context, byte contextSz) { ed_starts++; assert(n==expected_ed_sig_sz && memcmp(sig,expected_ed_sig,n)==0); ed_message_sz=0; return 0; } static int wc_ed25519_verify_msg_update(const byte *p, word32 n, ed25519_key *key) { ed_updates++; assert(n<=sizeof(ed_message)-ed_message_sz); if (n != 0) memcpy(ed_message+ed_message_sz,p,n); ed_message_sz+=n; return 0; } static int wc_ed25519_verify_msg_final(const byte *sig, word32 n, int *status, ed25519_key *key) { ed_finals++; assert(n==expected_ed_sig_sz && memcmp(sig,expected_ed_sig,n)==0); *status=!verify_failure; return 0; } #include "actual.c" static void parsers(byte *end) { struct context ctx = {0}; WOLFSSH ssh = {.ctx=&ctx, .clientState=9}; const word32 lengths[] = {0,1,2,3,4,27,28,31,32,33,255,UINT32_MAX-4,UINT32_MAX}; for (word32 n=0; n<=64; n++) { byte *p=end-n; for (unsigned j=0; j=4) put(p,lengths[j]); word32 idx=0, value=123; int good=n>=4 && lengths[j]<=n-4; assert(GetSize(&value,p,n,&idx)==(good?0:WS_BUFFER_E)); idx=0; assert(DoIgnore(&ssh,p,n,&idx)==(good?0:WS_BUFFER_E)); if (good) assert(idx==4+lengths[j]); idx=0; ssh.clientState=9; int bounded=good && lengths[j]UINT32_MAX-values[a]; assert(DoChannelWindowAdjust(&ssh,p,11,&idx)==(overflow?WS_OVERFLOW_E:0)); assert(channel.peerWindowSz==(overflow?values[a]:values[a]+values[b])); assert(idx==11); cases++; } byte p[8]={0}; word32 idx=0; channel.peerWindowSz=12; assert(DoChannelWindowAdjust(&ssh,p,8,&idx)==WS_INVALID_CHANID); assert(channel.peerWindowSz==12); } static word32 string(byte *p, const byte *s, word32 n) { put(p,n); memcpy(p+4,s,n); return n+4; } static void ecc(byte *end) { const byte type[]="ecdsa-sha2-nistp256"; const word32 size=sizeof(type)-1; byte *expected=end-size; memcpy(expected,type,size); struct context ctx={0}; WOLFSSH ssh={.ctx=&ctx}; byte digest[32]={0}; for(int which=0;which<2;which++) for(int mode=0;mode<6;mode++) { byte key[128]={0},sig[128]={0}, bad[40]={0}; memcpy(bad,type,size); word32 n=size; if(mode==1) bad[0]='X'; /* equal length mismatch */ if(mode==2) n--; /* matching prefix, shorter */ if(mode==3) n++; /* expected ends at guard page */ if(mode==4) n=0; if(mode==5) n=sizeof(bad); word32 k=string(key,which==0?bad:type,which==0?n:size); k+=string(key+k,(const byte*)"nistp256",8); k+=string(key+k,(const byte*)"Q",1); word32 s=string(sig,which==1?bad:type,which==1?n:size); put(sig+s,10); s+=4; s+=string(sig+s,(const byte*)"r",1); s+=string(sig+s,(const byte*)"s",1); WS_UserAuthData_PublicKey pk={.publicKey=key, .publicKeyType=expected, .signature=sig, .publicKeySz=k, .publicKeyTypeSz=size, .signatureSz=s}; imports=converts=verifies=0; int ret=DoUserAuthRequestEcc(&ssh,&pk,HASH_SHA256,digest,sizeof(digest)); if(mode==0) assert(ret==0 && imports==1 && converts==1 && verifies==1); else { assert(ret==(which==0?WS_CRYPTO_FAILED:WS_INVALID_ALGO_ID)); assert(imports==(unsigned)which && converts==0 && verifies==0); } cases++; if (mode==0 && which==0) { for (word32 cut=0; cut0); byte *map=mmap(NULL,(size_t)page*2,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANONYMOUS,-1,0); assert(map!=MAP_FAILED && mprotect(map+page,page,PROT_NONE)==0); parsers(map+page); windows(map+page); ecc(map+page); remaining_parsers(map+page); ecc_framing(map+page); ed25519_framing(map+page); assert(munmap(map,(size_t)page*2)==0); printf("PASS: %u parser/window/ECC/Ed25519 cases, guard pages + UBSan trap\n",cases); return 0; }