int sshbuf_put_string(struct sshbuf *buf, const void *v, size_t len) { u_char *d; int r; if (len > SSHBUF_SIZE_MAX - 4) { SSHBUF_DBG(("SSH_ERR_NO_BUFFER_SPACE")); return SSH_ERR_NO_BUFFER_SPACE; } if ((r = sshbuf_reserve(buf, len + 4, &d)) < 0) return r; POKE_U32(d, len); if (len != 0) memcpy(d + 4, v, len); return 0; }
int sshbuf_get_stringb(struct sshbuf *buf, struct sshbuf *v) { u_int32_t len; u_char *p; int r; /* * Use sshbuf_peek_string_direct() to figure out if there is * a complete string in 'buf' and copy the string directly * into 'v'. */ if ((r = sshbuf_peek_string_direct(buf, NULL, NULL)) != 0 || (r = sshbuf_get_u32(buf, &len)) != 0 || (r = sshbuf_reserve(v, len, &p)) != 0 || (r = sshbuf_get(buf, p, len)) != 0) return r; return 0; }
int sshbuf_put_bignum1(struct sshbuf *buf, const BIGNUM *v) { int r, len_bits = BN_num_bits(v); size_t len_bytes = (len_bits + 7) / 8; u_char d[SSHBUF_MAX_BIGNUM], *dp; if (len_bits < 0 || len_bytes > SSHBUF_MAX_BIGNUM) return SSH_ERR_INVALID_ARGUMENT; if (BN_bn2bin(v, d) != (int)len_bytes) return SSH_ERR_INTERNAL_ERROR; /* Shouldn't happen */ if ((r = sshbuf_reserve(buf, len_bytes + 2, &dp)) < 0) { bzero(d, sizeof(d)); return r; } POKE_U16(dp, len_bits); memcpy(dp + 2, d, len_bytes); bzero(d, sizeof(d)); return 0; }
int kex_c25519_keypair(struct kex *kex) { struct sshbuf *buf = NULL; u_char *cp = NULL; int r; if ((buf = sshbuf_new()) == NULL) return SSH_ERR_ALLOC_FAIL; if ((r = sshbuf_reserve(buf, CURVE25519_SIZE, &cp)) != 0) goto out; kexc25519_keygen(kex->c25519_client_key, cp); #ifdef DEBUG_KEXECDH dump_digest("client public key c25519:", cp, CURVE25519_SIZE); #endif kex->client_pub = buf; buf = NULL; out: sshbuf_free(buf); return r; }
void sshbuf_tests(void) { struct sshbuf *p1; const u_char *cdp; u_char *dp; size_t sz; int r; TEST_START("allocate sshbuf"); p1 = sshbuf_new(); ASSERT_PTR_NE(p1, NULL); TEST_DONE(); TEST_START("max size on fresh buffer"); ASSERT_SIZE_T_GT(sshbuf_max_size(p1), 0); TEST_DONE(); TEST_START("available on fresh buffer"); ASSERT_SIZE_T_GT(sshbuf_avail(p1), 0); TEST_DONE(); TEST_START("len = 0 on empty buffer"); ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0); TEST_DONE(); TEST_START("set valid max size"); ASSERT_INT_EQ(sshbuf_set_max_size(p1, 65536), 0); ASSERT_SIZE_T_EQ(sshbuf_max_size(p1), 65536); TEST_DONE(); TEST_START("available on limited buffer"); ASSERT_SIZE_T_EQ(sshbuf_avail(p1), 65536); TEST_DONE(); TEST_START("free"); sshbuf_free(p1); TEST_DONE(); TEST_START("consume on empty buffer"); p1 = sshbuf_new(); ASSERT_PTR_NE(p1, NULL); ASSERT_INT_EQ(sshbuf_consume(p1, 0), 0); ASSERT_INT_EQ(sshbuf_consume(p1, 1), SSH_ERR_MESSAGE_INCOMPLETE); sshbuf_free(p1); TEST_DONE(); TEST_START("consume_end on empty buffer"); p1 = sshbuf_new(); ASSERT_PTR_NE(p1, NULL); ASSERT_INT_EQ(sshbuf_consume_end(p1, 0), 0); ASSERT_INT_EQ(sshbuf_consume_end(p1, 1), SSH_ERR_MESSAGE_INCOMPLETE); sshbuf_free(p1); TEST_DONE(); TEST_START("reserve space"); p1 = sshbuf_new(); ASSERT_PTR_NE(p1, NULL); r = sshbuf_reserve(p1, 1, &dp); ASSERT_INT_EQ(r, 0); ASSERT_PTR_NE(dp, NULL); *dp = 0x11; r = sshbuf_reserve(p1, 3, &dp); ASSERT_INT_EQ(r, 0); ASSERT_PTR_NE(dp, NULL); *dp++ = 0x22; *dp++ = 0x33; *dp++ = 0x44; TEST_DONE(); TEST_START("sshbuf_len on filled buffer"); ASSERT_SIZE_T_EQ(sshbuf_len(p1), 4); TEST_DONE(); TEST_START("sshbuf_ptr on filled buffer"); cdp = sshbuf_ptr(p1); ASSERT_PTR_NE(cdp, NULL); ASSERT_U8_EQ(cdp[0], 0x11); ASSERT_U8_EQ(cdp[1], 0x22); ASSERT_U8_EQ(cdp[2], 0x33); ASSERT_U8_EQ(cdp[3], 0x44); TEST_DONE(); TEST_START("consume on filled buffer"); ASSERT_SIZE_T_EQ(sshbuf_len(p1), 4); ASSERT_INT_EQ(sshbuf_consume(p1, 0), 0); ASSERT_SIZE_T_EQ(sshbuf_len(p1), 4); r = sshbuf_consume(p1, 64); ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE); ASSERT_SIZE_T_EQ(sshbuf_len(p1), 4); ASSERT_INT_EQ(sshbuf_consume(p1, 1), 0); ASSERT_SIZE_T_EQ(sshbuf_len(p1), 3); cdp = sshbuf_ptr(p1); ASSERT_PTR_NE(p1, NULL); ASSERT_U8_EQ(cdp[0], 0x22); ASSERT_INT_EQ(sshbuf_consume(p1, 2), 0); ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1); cdp = sshbuf_ptr(p1); ASSERT_PTR_NE(p1, NULL); ASSERT_U8_EQ(cdp[0], 0x44); r = sshbuf_consume(p1, 2); ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE); ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1); ASSERT_INT_EQ(sshbuf_consume(p1, 1), 0); ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0); r = sshbuf_consume(p1, 1); ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE); sshbuf_free(p1); TEST_DONE(); TEST_START("consume_end on filled buffer"); p1 = sshbuf_new(); ASSERT_PTR_NE(p1, NULL); r = sshbuf_reserve(p1, 4, &dp); ASSERT_INT_EQ(r, 0); ASSERT_PTR_NE(dp, NULL); *dp++ = 0x11; *dp++ = 0x22; *dp++ = 0x33; *dp++ = 0x44; ASSERT_SIZE_T_EQ(sshbuf_len(p1), 4); r = sshbuf_consume_end(p1, 5); ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE); ASSERT_SIZE_T_EQ(sshbuf_len(p1), 4); ASSERT_INT_EQ(sshbuf_consume_end(p1, 3), 0); ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1); cdp = sshbuf_ptr(p1); ASSERT_PTR_NE(cdp, NULL); ASSERT_U8_EQ(*cdp, 0x11); r = sshbuf_consume_end(p1, 2); ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE); ASSERT_INT_EQ(sshbuf_consume_end(p1, 1), 0); ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0); sshbuf_free(p1); TEST_DONE(); TEST_START("fill limited buffer"); p1 = sshbuf_new(); ASSERT_PTR_NE(p1, NULL); ASSERT_INT_EQ(sshbuf_set_max_size(p1, 1223), 0); ASSERT_SIZE_T_EQ(sshbuf_max_size(p1), 1223); ASSERT_SIZE_T_EQ(sshbuf_avail(p1), 1223); r = sshbuf_reserve(p1, 1223, &dp); ASSERT_INT_EQ(r, 0); ASSERT_PTR_NE(dp, NULL); memset(dp, 0xd7, 1223); ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1223); ASSERT_SIZE_T_EQ(sshbuf_avail(p1), 0); r = sshbuf_reserve(p1, 1, &dp); ASSERT_INT_EQ(r, SSH_ERR_NO_BUFFER_SPACE); ASSERT_PTR_EQ(dp, NULL); TEST_DONE(); TEST_START("consume and force compaction"); ASSERT_INT_EQ(sshbuf_consume(p1, 223), 0); ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1000); ASSERT_SIZE_T_EQ(sshbuf_avail(p1), 223); r = sshbuf_reserve(p1, 224, &dp); ASSERT_INT_EQ(r, SSH_ERR_NO_BUFFER_SPACE); ASSERT_PTR_EQ(dp, NULL); ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1000); ASSERT_SIZE_T_EQ(sshbuf_avail(p1), 223); r = sshbuf_reserve(p1, 223, &dp); ASSERT_INT_EQ(r, 0); ASSERT_PTR_NE(dp, NULL); memset(dp, 0x7d, 223); cdp = sshbuf_ptr(p1); ASSERT_PTR_NE(cdp, NULL); ASSERT_MEM_FILLED_EQ(cdp, 0xd7, 1000); ASSERT_MEM_FILLED_EQ(cdp + 1000, 0x7d, 223); TEST_DONE(); TEST_START("resize full buffer"); r = sshbuf_set_max_size(p1, 1000); ASSERT_INT_EQ(r, SSH_ERR_NO_BUFFER_SPACE); sz = roundup(1223 + SSHBUF_SIZE_INC * 3, SSHBUF_SIZE_INC); ASSERT_INT_EQ(sshbuf_set_max_size(p1, sz), 0); ASSERT_SIZE_T_EQ(sshbuf_max_size(p1), sz); ASSERT_SIZE_T_EQ(sshbuf_avail(p1), sz - 1223); ASSERT_INT_EQ(sshbuf_len(p1), 1223); TEST_DONE(); /* NB. uses sshbuf internals */ TEST_START("alloc chunking"); r = sshbuf_reserve(p1, 1, &dp); ASSERT_INT_EQ(r, 0); ASSERT_PTR_NE(dp, NULL); *dp = 0xff; cdp = sshbuf_ptr(p1); ASSERT_PTR_NE(cdp, NULL); ASSERT_MEM_FILLED_EQ(cdp, 0xd7, 1000); ASSERT_MEM_FILLED_EQ(cdp + 1000, 0x7d, 223); ASSERT_MEM_FILLED_EQ(cdp + 1223, 0xff, 1); ASSERT_SIZE_T_EQ(sshbuf_alloc(p1) % SSHBUF_SIZE_INC, 0); sshbuf_free(p1); TEST_DONE(); TEST_START("reset buffer"); p1 = sshbuf_new(); ASSERT_PTR_NE(p1, NULL); ASSERT_INT_EQ(sshbuf_set_max_size(p1, 1223), 0); ASSERT_SIZE_T_EQ(sshbuf_max_size(p1), 1223); r = sshbuf_reserve(p1, 1223, &dp); ASSERT_INT_EQ(r, 0); ASSERT_PTR_NE(dp, NULL); memset(dp, 0xd7, 1223); ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1223); sshbuf_reset(p1); ASSERT_SIZE_T_EQ(sshbuf_max_size(p1), 1223); ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0); ASSERT_SIZE_T_EQ(sshbuf_avail(p1), 1223); sshbuf_free(p1); TEST_DONE(); }
/* * Serialises the authentication (private) key to a blob, encrypting it with * passphrase. The identification of the blob (lowest 64 bits of n) will * precede the key to provide identification of the key without needing a * passphrase. */ static int sshkey_private_rsa1_to_blob(struct sshkey *key, struct sshbuf *blob, const char *passphrase, const char *comment) { struct sshbuf *buffer = NULL, *encrypted = NULL; u_char buf[8]; int r, cipher_num; struct sshcipher_ctx ciphercontext; const struct sshcipher *cipher; u_char *cp; /* * If the passphrase is empty, use SSH_CIPHER_NONE to ease converting * to another cipher; otherwise use SSH_AUTHFILE_CIPHER. */ cipher_num = (strcmp(passphrase, "") == 0) ? SSH_CIPHER_NONE : SSH_AUTHFILE_CIPHER; if ((cipher = cipher_by_number(cipher_num)) == NULL) return SSH_ERR_INTERNAL_ERROR; /* This buffer is used to build the secret part of the private key. */ if ((buffer = sshbuf_new()) == NULL) return SSH_ERR_ALLOC_FAIL; /* Put checkbytes for checking passphrase validity. */ if ((r = sshbuf_reserve(buffer, 4, &cp)) != 0) goto out; arc4random_buf(cp, 2); memcpy(cp + 2, cp, 2); /* * Store the private key (n and e will not be stored because they * will be stored in plain text, and storing them also in encrypted * format would just give known plaintext). * Note: q and p are stored in reverse order to SSL. */ if ((r = sshbuf_put_bignum1(buffer, key->rsa->d)) != 0 || (r = sshbuf_put_bignum1(buffer, key->rsa->iqmp)) != 0 || (r = sshbuf_put_bignum1(buffer, key->rsa->q)) != 0 || (r = sshbuf_put_bignum1(buffer, key->rsa->p)) != 0) goto out; /* Pad the part to be encrypted to a size that is a multiple of 8. */ bzero(buf, 8); if ((r = sshbuf_put(buffer, buf, 8 - (sshbuf_len(buffer) % 8))) != 0) goto out; /* This buffer will be used to contain the data in the file. */ if ((encrypted = sshbuf_new()) == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } /* First store keyfile id string. */ if ((r = sshbuf_put(encrypted, authfile_id_string, sizeof(authfile_id_string))) != 0) goto out; /* Store cipher type and "reserved" field. */ if ((r = sshbuf_put_u8(encrypted, cipher_num)) != 0 || (r = sshbuf_put_u32(encrypted, 0)) != 0) goto out; /* Store public key. This will be in plain text. */ if ((r = sshbuf_put_u32(encrypted, BN_num_bits(key->rsa->n))) != 0 || (r = sshbuf_put_bignum1(encrypted, key->rsa->n) != 0) || (r = sshbuf_put_bignum1(encrypted, key->rsa->e) != 0) || (r = sshbuf_put_cstring(encrypted, comment) != 0)) goto out; /* Allocate space for the private part of the key in the buffer. */ if ((r = sshbuf_reserve(encrypted, sshbuf_len(buffer), &cp)) != 0) goto out; if ((r = cipher_set_key_string(&ciphercontext, cipher, passphrase, CIPHER_ENCRYPT)) != 0) goto out; if ((r = cipher_crypt(&ciphercontext, cp, sshbuf_ptr(buffer), sshbuf_len(buffer), 0, 0)) != 0) goto out; if ((r = cipher_cleanup(&ciphercontext)) != 0) goto out; r = sshbuf_putb(blob, encrypted); out: bzero(&ciphercontext, sizeof(ciphercontext)); bzero(buf, sizeof(buf)); if (buffer != NULL) sshbuf_free(buffer); if (encrypted != NULL) sshbuf_free(encrypted); return r; }
static int sshkey_parse_private_rsa1(struct sshbuf *blob, const char *passphrase, struct sshkey **keyp, char **commentp) { int r; u_int16_t check1, check2; u_int8_t cipher_type; struct sshbuf *decrypted = NULL, *copy = NULL; u_char *cp; char *comment = NULL; struct sshcipher_ctx ciphercontext; const struct sshcipher *cipher; struct sshkey *prv = NULL; *keyp = NULL; if (commentp != NULL) *commentp = NULL; /* Check that it is at least big enough to contain the ID string. */ if (sshbuf_len(blob) < sizeof(authfile_id_string)) return SSH_ERR_INVALID_FORMAT; /* * Make sure it begins with the id string. Consume the id string * from the buffer. */ if (memcmp(sshbuf_ptr(blob), authfile_id_string, sizeof(authfile_id_string)) != 0) return SSH_ERR_INVALID_FORMAT; if ((prv = sshkey_new_private(KEY_RSA1)) == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } if ((copy = sshbuf_fromb(blob)) == NULL || (decrypted = sshbuf_new()) == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } if ((r = sshbuf_consume(copy, sizeof(authfile_id_string))) != 0) goto out; /* Read cipher type. */ if ((r = sshbuf_get_u8(copy, &cipher_type)) != 0 || (r = sshbuf_get_u32(copy, NULL)) != 0) /* reserved */ goto out; /* Read the public key and comment from the buffer. */ if ((r = sshbuf_get_u32(copy, NULL)) != 0 || /* key bits */ (r = sshbuf_get_bignum1(copy, prv->rsa->n)) != 0 || (r = sshbuf_get_bignum1(copy, prv->rsa->e)) != 0 || (r = sshbuf_get_cstring(copy, &comment, NULL)) != 0) goto out; /* Check that it is a supported cipher. */ cipher = cipher_by_number(cipher_type); if (cipher == NULL) { r = SSH_ERR_KEY_UNKNOWN_CIPHER; goto out; } /* Initialize space for decrypted data. */ if ((r = sshbuf_reserve(decrypted, sshbuf_len(copy), &cp)) != 0) goto out; /* Rest of the buffer is encrypted. Decrypt it using the passphrase. */ if ((r = cipher_set_key_string(&ciphercontext, cipher, passphrase, CIPHER_DECRYPT)) != 0) goto out; if ((r = cipher_crypt(&ciphercontext, cp, sshbuf_ptr(copy), sshbuf_len(copy), 0, 0)) != 0) { cipher_cleanup(&ciphercontext); goto out; } if ((r = cipher_cleanup(&ciphercontext)) != 0) goto out; if ((r = sshbuf_get_u16(decrypted, &check1)) != 0 || (r = sshbuf_get_u16(decrypted, &check2)) != 0) goto out; if (check1 != check2) { r = SSH_ERR_KEY_WRONG_PASSPHRASE; goto out; } /* Read the rest of the private key. */ if ((r = sshbuf_get_bignum1(decrypted, prv->rsa->d)) != 0 || (r = sshbuf_get_bignum1(decrypted, prv->rsa->iqmp)) != 0 || (r = sshbuf_get_bignum1(decrypted, prv->rsa->q)) != 0 || (r = sshbuf_get_bignum1(decrypted, prv->rsa->p)) != 0) goto out; /* calculate p-1 and q-1 */ if ((r = rsa_generate_additional_parameters(prv->rsa)) != 0) goto out; /* enable blinding */ if (RSA_blinding_on(prv->rsa, NULL) != 1) { r = SSH_ERR_LIBCRYPTO_ERROR; goto out; } r = 0; *keyp = prv; prv = NULL; if (commentp != NULL) { *commentp = comment; comment = NULL; } out: bzero(&ciphercontext, sizeof(ciphercontext)); if (comment != NULL) free(comment); if (prv != NULL) sshkey_free(prv); if (copy != NULL) sshbuf_free(copy); if (decrypted != NULL) sshbuf_free(decrypted); return r; }
void sshbuf_misc_tests(void) { struct sshbuf *p1; char tmp[512], *p; FILE *out; size_t sz; TEST_START("sshbuf_dump"); out = tmpfile(); ASSERT_PTR_NE(out, NULL); p1 = sshbuf_new(); ASSERT_PTR_NE(p1, NULL); ASSERT_INT_EQ(sshbuf_put_u32(p1, 0x12345678), 0); sshbuf_dump(p1, out); fflush(out); rewind(out); sz = fread(tmp, 1, sizeof(tmp), out); ASSERT_INT_EQ(ferror(out), 0); ASSERT_INT_NE(feof(out), 0); ASSERT_SIZE_T_GT(sz, 0); tmp[sz] = '\0'; ASSERT_PTR_NE(strstr(tmp, "12 34 56 78"), NULL); fclose(out); sshbuf_free(p1); TEST_DONE(); TEST_START("sshbuf_dtob16"); p1 = sshbuf_new(); ASSERT_PTR_NE(p1, NULL); ASSERT_INT_EQ(sshbuf_put_u32(p1, 0x12345678), 0); p = sshbuf_dtob16(p1); ASSERT_PTR_NE(p, NULL); ASSERT_STRING_EQ(p, "12345678"); free(p); sshbuf_free(p1); TEST_DONE(); TEST_START("sshbuf_dtob64 len 1"); p1 = sshbuf_new(); ASSERT_PTR_NE(p1, NULL); ASSERT_INT_EQ(sshbuf_put_u8(p1, 0x11), 0); p = sshbuf_dtob64(p1); ASSERT_PTR_NE(p, NULL); ASSERT_STRING_EQ(p, "EQ=="); free(p); sshbuf_free(p1); TEST_DONE(); TEST_START("sshbuf_dtob64 len 2"); p1 = sshbuf_new(); ASSERT_PTR_NE(p1, NULL); ASSERT_INT_EQ(sshbuf_put_u8(p1, 0x11), 0); ASSERT_INT_EQ(sshbuf_put_u8(p1, 0x22), 0); p = sshbuf_dtob64(p1); ASSERT_PTR_NE(p, NULL); ASSERT_STRING_EQ(p, "ESI="); free(p); sshbuf_free(p1); TEST_DONE(); TEST_START("sshbuf_dtob64 len 3"); p1 = sshbuf_new(); ASSERT_PTR_NE(p1, NULL); ASSERT_INT_EQ(sshbuf_put_u8(p1, 0x11), 0); ASSERT_INT_EQ(sshbuf_put_u8(p1, 0x22), 0); ASSERT_INT_EQ(sshbuf_put_u8(p1, 0x33), 0); p = sshbuf_dtob64(p1); ASSERT_PTR_NE(p, NULL); ASSERT_STRING_EQ(p, "ESIz"); free(p); sshbuf_free(p1); TEST_DONE(); TEST_START("sshbuf_dtob64 len 8191"); p1 = sshbuf_new(); ASSERT_PTR_NE(p1, NULL); ASSERT_INT_EQ(sshbuf_reserve(p1, 8192, NULL), 0); bzero(sshbuf_mutable_ptr(p1), 8192); p = sshbuf_dtob64(p1); ASSERT_PTR_NE(p, NULL); ASSERT_SIZE_T_EQ(strlen(p), ((8191 + 2) / 3) * 4); free(p); sshbuf_free(p1); TEST_DONE(); TEST_START("sshbuf_b64tod len 1"); p1 = sshbuf_new(); ASSERT_PTR_NE(p1, NULL); ASSERT_INT_EQ(sshbuf_b64tod(p1, "0A=="), 0); ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1); ASSERT_U8_EQ(*sshbuf_ptr(p1), 0xd0); sshbuf_free(p1); TEST_DONE(); TEST_START("sshbuf_b64tod len 2"); p1 = sshbuf_new(); ASSERT_PTR_NE(p1, NULL); ASSERT_INT_EQ(sshbuf_b64tod(p1, "0A8="), 0); ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2); ASSERT_U16_EQ(PEEK_U16(sshbuf_ptr(p1)), 0xd00f); sshbuf_free(p1); TEST_DONE(); TEST_START("sshbuf_b64tod len 4"); p1 = sshbuf_new(); ASSERT_PTR_NE(p1, NULL); ASSERT_INT_EQ(sshbuf_b64tod(p1, "0A/QDw=="), 0); ASSERT_SIZE_T_EQ(sshbuf_len(p1), 4); ASSERT_U32_EQ(PEEK_U32(sshbuf_ptr(p1)), 0xd00fd00f); sshbuf_free(p1); TEST_DONE(); }
void sshbuf_getput_crypto_tests(void) { struct sshbuf *p1; const u_char *d; size_t s; BIGNUM *bn, *bn2, *bn_x, *bn_y; /* This one has num_bits != num_bytes * 8 to test bignum1 encoding */ const char *hexbn1 = "0102030405060708090a0b0c0d0e0f10"; /* This one has MSB set to test bignum2 encoding negative-avoidance */ const char *hexbn2 = "f0e0d0c0b0a0908070605040302010007fff11"; u_char expbn1[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, }; u_char expbn2[] = { 0xf0, 0xe0, 0xd0, 0xc0, 0xb0, 0xa0, 0x90, 0x80, 0x70, 0x60, 0x50, 0x40, 0x30, 0x20, 0x10, 0x00, 0x7f, 0xff, 0x11 }; int ec256_nid = NID_X9_62_prime256v1; char *ec256_x = "0C828004839D0106AA59575216191357" "34B451459DADB586677EF9DF55784999"; char *ec256_y = "4D196B50F0B4E94B3C73E3A9D4CD9DF2" "C8F9A35E42BDD047550F69D80EC23CD4"; u_char expec256[] = { 0x04, 0x0c, 0x82, 0x80, 0x04, 0x83, 0x9d, 0x01, 0x06, 0xaa, 0x59, 0x57, 0x52, 0x16, 0x19, 0x13, 0x57, 0x34, 0xb4, 0x51, 0x45, 0x9d, 0xad, 0xb5, 0x86, 0x67, 0x7e, 0xf9, 0xdf, 0x55, 0x78, 0x49, 0x99, 0x4d, 0x19, 0x6b, 0x50, 0xf0, 0xb4, 0xe9, 0x4b, 0x3c, 0x73, 0xe3, 0xa9, 0xd4, 0xcd, 0x9d, 0xf2, 0xc8, 0xf9, 0xa3, 0x5e, 0x42, 0xbd, 0xd0, 0x47, 0x55, 0x0f, 0x69, 0xd8, 0x0e, 0xc2, 0x3c, 0xd4 }; EC_KEY *eck; EC_POINT *ecp; int r; #define MKBN(b, bnn) \ do { \ bnn = NULL; \ ASSERT_INT_GT(BN_hex2bn(&bnn, b), 0); \ } while (0) TEST_START("sshbuf_put_bignum1"); MKBN(hexbn1, bn); p1 = sshbuf_new(); ASSERT_PTR_NE(p1, NULL); ASSERT_INT_EQ(sshbuf_put_bignum1(p1, bn), 0); ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(expbn1) + 2); ASSERT_U16_EQ(PEEK_U16(sshbuf_ptr(p1)), (u_int16_t)BN_num_bits(bn)); ASSERT_MEM_EQ(sshbuf_ptr(p1) + 2, expbn1, sizeof(expbn1)); BN_free(bn); sshbuf_free(p1); TEST_DONE(); TEST_START("sshbuf_put_bignum1 limited"); MKBN(hexbn1, bn); p1 = sshbuf_new(); ASSERT_PTR_NE(p1, NULL); ASSERT_INT_EQ(sshbuf_set_max_size(p1, sizeof(expbn1) + 1), 0); r = sshbuf_put_bignum1(p1, bn); ASSERT_INT_EQ(r, SSH_ERR_NO_BUFFER_SPACE); ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0); BN_free(bn); sshbuf_free(p1); TEST_DONE(); TEST_START("sshbuf_put_bignum1 bn2"); MKBN(hexbn2, bn); p1 = sshbuf_new(); ASSERT_PTR_NE(p1, NULL); ASSERT_INT_EQ(sshbuf_put_bignum1(p1, bn), 0); ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(expbn2) + 2); ASSERT_U16_EQ(PEEK_U16(sshbuf_ptr(p1)), (u_int16_t)BN_num_bits(bn)); ASSERT_MEM_EQ(sshbuf_ptr(p1) + 2, expbn2, sizeof(expbn2)); BN_free(bn); sshbuf_free(p1); TEST_DONE(); TEST_START("sshbuf_put_bignum1 bn2 limited"); MKBN(hexbn2, bn); p1 = sshbuf_new(); ASSERT_PTR_NE(p1, NULL); ASSERT_INT_EQ(sshbuf_set_max_size(p1, sizeof(expbn1) + 1), 0); r = sshbuf_put_bignum1(p1, bn); ASSERT_INT_EQ(r, SSH_ERR_NO_BUFFER_SPACE); ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0); BN_free(bn); sshbuf_free(p1); TEST_DONE(); TEST_START("sshbuf_put_bignum2"); MKBN(hexbn1, bn); p1 = sshbuf_new(); ASSERT_PTR_NE(p1, NULL); ASSERT_INT_EQ(sshbuf_put_bignum2(p1, bn), 0); ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(expbn1) + 4); ASSERT_U32_EQ(PEEK_U32(sshbuf_ptr(p1)), (u_int32_t)BN_num_bytes(bn)); ASSERT_MEM_EQ(sshbuf_ptr(p1) + 4, expbn1, sizeof(expbn1)); BN_free(bn); sshbuf_free(p1); TEST_DONE(); TEST_START("sshbuf_put_bignum2 limited"); MKBN(hexbn1, bn); p1 = sshbuf_new(); ASSERT_PTR_NE(p1, NULL); ASSERT_INT_EQ(sshbuf_set_max_size(p1, sizeof(expbn1) + 3), 0); r = sshbuf_put_bignum2(p1, bn); ASSERT_INT_EQ(r, SSH_ERR_NO_BUFFER_SPACE); ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0); BN_free(bn); sshbuf_free(p1); TEST_DONE(); TEST_START("sshbuf_put_bignum2 bn2"); MKBN(hexbn2, bn); p1 = sshbuf_new(); ASSERT_PTR_NE(p1, NULL); ASSERT_INT_EQ(sshbuf_put_bignum2(p1, bn), 0); ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(expbn2) + 4 + 1); /* MSB */ ASSERT_U32_EQ(PEEK_U32(sshbuf_ptr(p1)), (u_int32_t)BN_num_bytes(bn) + 1); ASSERT_U8_EQ(*(sshbuf_ptr(p1) + 4), 0x00); ASSERT_MEM_EQ(sshbuf_ptr(p1) + 5, expbn2, sizeof(expbn2)); BN_free(bn); sshbuf_free(p1); TEST_DONE(); TEST_START("sshbuf_put_bignum2 bn2 limited"); MKBN(hexbn2, bn); p1 = sshbuf_new(); ASSERT_PTR_NE(p1, NULL); ASSERT_INT_EQ(sshbuf_set_max_size(p1, sizeof(expbn2) + 3), 0); r = sshbuf_put_bignum2(p1, bn); ASSERT_INT_EQ(r, SSH_ERR_NO_BUFFER_SPACE); ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0); BN_free(bn); sshbuf_free(p1); TEST_DONE(); TEST_START("sshbuf_get_bignum1"); MKBN(hexbn1, bn); p1 = sshbuf_new(); ASSERT_PTR_NE(p1, NULL); ASSERT_INT_EQ(sshbuf_put_u16(p1, BN_num_bits(bn)), 0); ASSERT_INT_EQ(sshbuf_put(p1, expbn1, sizeof(expbn1)), 0); ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2 + sizeof(expbn1)); ASSERT_INT_EQ(sshbuf_put_u16(p1, 0xd00f), 0); bn2 = BN_new(); ASSERT_INT_EQ(sshbuf_get_bignum1(p1, bn2), 0); ASSERT_BIGNUM_EQ(bn, bn2); ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2); BN_free(bn); BN_free(bn2); sshbuf_free(p1); TEST_DONE(); TEST_START("sshbuf_get_bignum1 truncated"); MKBN(hexbn1, bn); p1 = sshbuf_new(); ASSERT_PTR_NE(p1, NULL); ASSERT_INT_EQ(sshbuf_put_u16(p1, BN_num_bits(bn)), 0); ASSERT_INT_EQ(sshbuf_put(p1, expbn1, sizeof(expbn1) - 1), 0); ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2 + sizeof(expbn1) - 1); bn2 = BN_new(); r = sshbuf_get_bignum1(p1, bn2); ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE); ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2 + sizeof(expbn1) - 1); BN_free(bn); BN_free(bn2); sshbuf_free(p1); TEST_DONE(); TEST_START("sshbuf_get_bignum1 giant"); MKBN(hexbn1, bn); p1 = sshbuf_new(); ASSERT_PTR_NE(p1, NULL); ASSERT_INT_EQ(sshbuf_put_u16(p1, 0xffff), 0); ASSERT_INT_EQ(sshbuf_reserve(p1, (0xffff + 7) / 8, NULL), 0); ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2 + ((0xffff + 7) / 8)); bn2 = BN_new(); r = sshbuf_get_bignum1(p1, bn2); ASSERT_INT_EQ(r, SSH_ERR_BIGNUM_TOO_LARGE); ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2 + ((0xffff + 7) / 8)); BN_free(bn); BN_free(bn2); sshbuf_free(p1); TEST_DONE(); TEST_START("sshbuf_get_bignum1 bn2"); MKBN(hexbn2, bn); p1 = sshbuf_new(); ASSERT_PTR_NE(p1, NULL); ASSERT_INT_EQ(sshbuf_put_u16(p1, BN_num_bits(bn)), 0); ASSERT_INT_EQ(sshbuf_put(p1, expbn2, sizeof(expbn2)), 0); ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2 + sizeof(expbn2)); ASSERT_INT_EQ(sshbuf_put_u16(p1, 0xd00f), 0); bn2 = BN_new(); ASSERT_INT_EQ(sshbuf_get_bignum1(p1, bn2), 0); ASSERT_BIGNUM_EQ(bn, bn2); ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2); BN_free(bn); BN_free(bn2); sshbuf_free(p1); TEST_DONE(); TEST_START("sshbuf_get_bignum1 bn2 truncated"); MKBN(hexbn2, bn); p1 = sshbuf_new(); ASSERT_PTR_NE(p1, NULL); ASSERT_INT_EQ(sshbuf_put_u16(p1, BN_num_bits(bn)), 0); ASSERT_INT_EQ(sshbuf_put(p1, expbn2, sizeof(expbn2) - 1), 0); ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2 + sizeof(expbn2) - 1); bn2 = BN_new(); r = sshbuf_get_bignum1(p1, bn2); ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE); ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2 + sizeof(expbn2) - 1); BN_free(bn); BN_free(bn2); sshbuf_free(p1); TEST_DONE(); TEST_START("sshbuf_get_bignum2"); MKBN(hexbn1, bn); p1 = sshbuf_new(); ASSERT_PTR_NE(p1, NULL); ASSERT_INT_EQ(sshbuf_put_u32(p1, BN_num_bytes(bn)), 0); ASSERT_INT_EQ(sshbuf_put(p1, expbn1, sizeof(expbn1)), 0); ASSERT_SIZE_T_EQ(sshbuf_len(p1), 4 + sizeof(expbn1)); ASSERT_INT_EQ(sshbuf_put_u16(p1, 0xd00f), 0); bn2 = BN_new(); ASSERT_INT_EQ(sshbuf_get_bignum2(p1, bn2), 0); ASSERT_BIGNUM_EQ(bn, bn2); ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2); BN_free(bn); BN_free(bn2); sshbuf_free(p1); TEST_DONE(); TEST_START("sshbuf_get_bignum2 truncated"); MKBN(hexbn1, bn); p1 = sshbuf_new(); ASSERT_PTR_NE(p1, NULL); ASSERT_INT_EQ(sshbuf_put_u32(p1, BN_num_bytes(bn)), 0); ASSERT_INT_EQ(sshbuf_put(p1, expbn1, sizeof(expbn1) - 1), 0); bn2 = BN_new(); r = sshbuf_get_bignum2(p1, bn2); ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE); ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(expbn1) + 3); BN_free(bn); BN_free(bn2); sshbuf_free(p1); TEST_DONE(); TEST_START("sshbuf_get_bignum2 giant"); MKBN(hexbn1, bn); p1 = sshbuf_new(); ASSERT_PTR_NE(p1, NULL); ASSERT_INT_EQ(sshbuf_put_u32(p1, 65536), 0); ASSERT_INT_EQ(sshbuf_reserve(p1, 65536, NULL), 0); bn2 = BN_new(); r = sshbuf_get_bignum2(p1, bn2); ASSERT_INT_EQ(r, SSH_ERR_BIGNUM_TOO_LARGE); ASSERT_SIZE_T_EQ(sshbuf_len(p1), 65536 + 4); BN_free(bn); BN_free(bn2); sshbuf_free(p1); TEST_DONE(); TEST_START("sshbuf_get_bignum2 bn2"); MKBN(hexbn2, bn); p1 = sshbuf_new(); ASSERT_PTR_NE(p1, NULL); ASSERT_INT_EQ(sshbuf_put_u32(p1, BN_num_bytes(bn) + 1), 0); /* MSB */ ASSERT_INT_EQ(sshbuf_put_u8(p1, 0x00), 0); ASSERT_INT_EQ(sshbuf_put(p1, expbn2, sizeof(expbn2)), 0); ASSERT_SIZE_T_EQ(sshbuf_len(p1), 4 + 1 + sizeof(expbn2)); ASSERT_INT_EQ(sshbuf_put_u16(p1, 0xd00f), 0); bn2 = BN_new(); ASSERT_INT_EQ(sshbuf_get_bignum2(p1, bn2), 0); ASSERT_BIGNUM_EQ(bn, bn2); ASSERT_SIZE_T_EQ(sshbuf_len(p1), 2); BN_free(bn); BN_free(bn2); sshbuf_free(p1); TEST_DONE(); TEST_START("sshbuf_get_bignum2 bn2 truncated"); MKBN(hexbn2, bn); p1 = sshbuf_new(); ASSERT_PTR_NE(p1, NULL); ASSERT_INT_EQ(sshbuf_put_u32(p1, BN_num_bytes(bn) + 1), 0); ASSERT_INT_EQ(sshbuf_put_u8(p1, 0x00), 0); ASSERT_INT_EQ(sshbuf_put(p1, expbn2, sizeof(expbn2) - 1), 0); bn2 = BN_new(); r = sshbuf_get_bignum2(p1, bn2); ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE); ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(expbn2) + 1 + 4 - 1); BN_free(bn); BN_free(bn2); sshbuf_free(p1); TEST_DONE(); TEST_START("sshbuf_get_bignum2 bn2 negative"); MKBN(hexbn2, bn); p1 = sshbuf_new(); ASSERT_PTR_NE(p1, NULL); ASSERT_INT_EQ(sshbuf_put_u32(p1, BN_num_bytes(bn)), 0); ASSERT_INT_EQ(sshbuf_put(p1, expbn2, sizeof(expbn2)), 0); bn2 = BN_new(); r = sshbuf_get_bignum2(p1, bn2); ASSERT_INT_EQ(r, SSH_ERR_BIGNUM_IS_NEGATIVE); ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(expbn2) + 4); BN_free(bn); BN_free(bn2); sshbuf_free(p1); TEST_DONE(); TEST_START("sshbuf_put_ec"); eck = EC_KEY_new_by_curve_name(ec256_nid); ASSERT_PTR_NE(eck, NULL); ecp = EC_POINT_new(EC_KEY_get0_group(eck)); ASSERT_PTR_NE(ecp, NULL); MKBN(ec256_x, bn_x); MKBN(ec256_y, bn_y); ASSERT_INT_EQ(EC_POINT_set_affine_coordinates_GFp( EC_KEY_get0_group(eck), ecp, bn_x, bn_y, NULL), 1); ASSERT_INT_EQ(EC_KEY_set_public_key(eck, ecp), 1); EC_POINT_free(ecp); p1 = sshbuf_new(); ASSERT_PTR_NE(p1, NULL); ASSERT_INT_EQ(sshbuf_put_eckey(p1, eck), 0); ASSERT_INT_EQ(sshbuf_get_string_direct(p1, &d, &s), 0); ASSERT_SIZE_T_EQ(s, sizeof(expec256)); ASSERT_MEM_EQ(d, expec256, sizeof(expec256)); sshbuf_free(p1); EC_KEY_free(eck); TEST_DONE(); TEST_START("sshbuf_get_ec"); eck = EC_KEY_new_by_curve_name(ec256_nid); ASSERT_PTR_NE(eck, NULL); p1 = sshbuf_new(); ASSERT_PTR_NE(p1, NULL); ASSERT_INT_EQ(sshbuf_put_string(p1, expec256, sizeof(expec256)), 0); ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(expec256) + 4); ASSERT_INT_EQ(sshbuf_put_u8(p1, 0x00), 0); ASSERT_INT_EQ(sshbuf_get_eckey(p1, eck), 0); bn_x = BN_new(); bn_y = BN_new(); ASSERT_PTR_NE(bn_x, NULL); ASSERT_PTR_NE(bn_y, NULL); ASSERT_INT_EQ(EC_POINT_get_affine_coordinates_GFp( EC_KEY_get0_group(eck), EC_KEY_get0_public_key(eck), bn_x, bn_y, NULL), 1); MKBN(ec256_x, bn); MKBN(ec256_y, bn2); ASSERT_INT_EQ(BN_cmp(bn_x, bn), 0); ASSERT_INT_EQ(BN_cmp(bn_y, bn2), 0); ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1); sshbuf_free(p1); EC_KEY_free(eck); BN_free(bn_x); BN_free(bn_y); BN_free(bn); BN_free(bn2); TEST_DONE(); }
int sshkey_xmss_decrypt_state(const struct sshkey *k, struct sshbuf *encoded, struct sshbuf **retp) { struct ssh_xmss_state *state = k->xmss_state; struct sshbuf *copy = NULL, *decrypted = NULL; struct sshcipher_ctx *ciphercontext = NULL; const struct sshcipher *cipher = NULL; u_char *key, *iv = NULL, *dp; size_t keylen, ivlen, authlen, aadlen; u_int blocksize, encrypted_len, index; int r = SSH_ERR_INTERNAL_ERROR; if (retp != NULL) *retp = NULL; if (state == NULL || state->enc_keyiv == NULL || state->enc_ciphername == NULL) return SSH_ERR_INTERNAL_ERROR; if ((cipher = cipher_by_name(state->enc_ciphername)) == NULL) { r = SSH_ERR_INVALID_FORMAT; goto out; } blocksize = cipher_blocksize(cipher); keylen = cipher_keylen(cipher); ivlen = cipher_ivlen(cipher); authlen = cipher_authlen(cipher); if (state->enc_keyiv_len != keylen + ivlen) { r = SSH_ERR_INTERNAL_ERROR; goto out; } key = state->enc_keyiv; if ((copy = sshbuf_fromb(encoded)) == NULL || (decrypted = sshbuf_new()) == NULL || (iv = malloc(ivlen)) == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } /* check magic */ if (sshbuf_len(encoded) < sizeof(XMSS_MAGIC) || memcmp(sshbuf_ptr(encoded), XMSS_MAGIC, sizeof(XMSS_MAGIC))) { r = SSH_ERR_INVALID_FORMAT; goto out; } /* parse public portion */ if ((r = sshbuf_consume(encoded, sizeof(XMSS_MAGIC))) != 0 || (r = sshbuf_get_u32(encoded, &index)) != 0 || (r = sshbuf_get_u32(encoded, &encrypted_len)) != 0) goto out; /* check size of encrypted key blob */ if (encrypted_len < blocksize || (encrypted_len % blocksize) != 0) { r = SSH_ERR_INVALID_FORMAT; goto out; } /* check that an appropriate amount of auth data is present */ if (sshbuf_len(encoded) < encrypted_len + authlen) { r = SSH_ERR_INVALID_FORMAT; goto out; } aadlen = sshbuf_len(copy) - sshbuf_len(encoded); /* replace first 4 bytes of IV with index to ensure uniqueness */ memcpy(iv, key + keylen, ivlen); POKE_U32(iv, index); /* decrypt private state of key */ if ((r = sshbuf_reserve(decrypted, aadlen + encrypted_len, &dp)) != 0 || (r = cipher_init(&ciphercontext, cipher, key, keylen, iv, ivlen, 0)) != 0 || (r = cipher_crypt(ciphercontext, 0, dp, sshbuf_ptr(copy), encrypted_len, aadlen, authlen)) != 0) goto out; /* there should be no trailing data */ if ((r = sshbuf_consume(encoded, encrypted_len + authlen)) != 0) goto out; if (sshbuf_len(encoded) != 0) { r = SSH_ERR_INVALID_FORMAT; goto out; } /* remove AAD */ if ((r = sshbuf_consume(decrypted, aadlen)) != 0) goto out; /* XXX encrypted includes unchecked padding */ /* success */ r = 0; if (retp != NULL) { *retp = decrypted; decrypted = NULL; } out: cipher_free(ciphercontext); sshbuf_free(copy); sshbuf_free(decrypted); free(iv); return r; }
int sshkey_xmss_encrypt_state(const struct sshkey *k, struct sshbuf *b, struct sshbuf **retp) { struct ssh_xmss_state *state = k->xmss_state; struct sshbuf *encrypted = NULL, *encoded = NULL, *padded = NULL; struct sshcipher_ctx *ciphercontext = NULL; const struct sshcipher *cipher; u_char *cp, *key, *iv = NULL; size_t i, keylen, ivlen, blocksize, authlen, encrypted_len, aadlen; int r = SSH_ERR_INTERNAL_ERROR; if (retp != NULL) *retp = NULL; if (state == NULL || state->enc_keyiv == NULL || state->enc_ciphername == NULL) return SSH_ERR_INTERNAL_ERROR; if ((cipher = cipher_by_name(state->enc_ciphername)) == NULL) { r = SSH_ERR_INTERNAL_ERROR; goto out; } blocksize = cipher_blocksize(cipher); keylen = cipher_keylen(cipher); ivlen = cipher_ivlen(cipher); authlen = cipher_authlen(cipher); if (state->enc_keyiv_len != keylen + ivlen) { r = SSH_ERR_INVALID_FORMAT; goto out; } key = state->enc_keyiv; if ((encrypted = sshbuf_new()) == NULL || (encoded = sshbuf_new()) == NULL || (padded = sshbuf_new()) == NULL || (iv = malloc(ivlen)) == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } /* replace first 4 bytes of IV with index to ensure uniqueness */ memcpy(iv, key + keylen, ivlen); POKE_U32(iv, state->idx); if ((r = sshbuf_put(encoded, XMSS_MAGIC, sizeof(XMSS_MAGIC))) != 0 || (r = sshbuf_put_u32(encoded, state->idx)) != 0) goto out; /* padded state will be encrypted */ if ((r = sshbuf_putb(padded, b)) != 0) goto out; i = 0; while (sshbuf_len(padded) % blocksize) { if ((r = sshbuf_put_u8(padded, ++i & 0xff)) != 0) goto out; } encrypted_len = sshbuf_len(padded); /* header including the length of state is used as AAD */ if ((r = sshbuf_put_u32(encoded, encrypted_len)) != 0) goto out; aadlen = sshbuf_len(encoded); /* concat header and state */ if ((r = sshbuf_putb(encoded, padded)) != 0) goto out; /* reserve space for encryption of encoded data plus auth tag */ /* encrypt at offset addlen */ if ((r = sshbuf_reserve(encrypted, encrypted_len + aadlen + authlen, &cp)) != 0 || (r = cipher_init(&ciphercontext, cipher, key, keylen, iv, ivlen, 1)) != 0 || (r = cipher_crypt(ciphercontext, 0, cp, sshbuf_ptr(encoded), encrypted_len, aadlen, authlen)) != 0) goto out; /* success */ r = 0; out: if (retp != NULL) { *retp = encrypted; encrypted = NULL; } sshbuf_free(padded); sshbuf_free(encoded); sshbuf_free(encrypted); cipher_free(ciphercontext); free(iv); return r; }
void sshbuf_fuzz_tests(void) { struct sshbuf *p1; u_char *dp; size_t sz, sz2, i; u_int32_t r; int ret; /* NB. uses sshbuf internals */ TEST_START("fuzz alloc/dealloc"); p1 = sshbuf_new(); ASSERT_INT_EQ(sshbuf_set_max_size(p1, 16 * 1024), 0); ASSERT_PTR_NE(p1, NULL); ASSERT_PTR_NE(sshbuf_ptr(p1), NULL); ASSERT_MEM_ZERO_NE(sshbuf_ptr(p1), sshbuf_len(p1)); for (i = 0; i < NUM_FUZZ_TESTS; i++) { r = arc4random_uniform(10); if (r == 0) { /* 10% chance: small reserve */ r = arc4random_uniform(10); fuzz_reserve: sz = sshbuf_avail(p1); sz2 = sshbuf_len(p1); ret = sshbuf_reserve(p1, r, &dp); if (ret < 0) { ASSERT_PTR_EQ(dp, NULL); ASSERT_SIZE_T_LT(sz, r); ASSERT_SIZE_T_EQ(sshbuf_avail(p1), sz); ASSERT_SIZE_T_EQ(sshbuf_len(p1), sz2); } else { ASSERT_PTR_NE(dp, NULL); ASSERT_SIZE_T_GE(sz, r); ASSERT_SIZE_T_EQ(sshbuf_avail(p1), sz - r); ASSERT_SIZE_T_EQ(sshbuf_len(p1), sz2 + r); memset(dp, arc4random_uniform(255) + 1, r); } } else if (r < 3) { /* 20% chance: big reserve */ r = arc4random_uniform(8 * 1024); goto fuzz_reserve; } else if (r == 3) { /* 10% chance: small consume */ r = arc4random_uniform(10); fuzz_consume: sz = sshbuf_avail(p1); sz2 = sshbuf_len(p1); /* 50% change consume from end, otherwise start */ ret = ((arc4random() & 1) ? sshbuf_consume : sshbuf_consume_end)(p1, r); if (ret < 0) { ASSERT_SIZE_T_LT(sz2, r); ASSERT_SIZE_T_EQ(sshbuf_avail(p1), sz); ASSERT_SIZE_T_EQ(sshbuf_len(p1), sz2); } else { ASSERT_SIZE_T_GE(sz2, r); ASSERT_SIZE_T_EQ(sshbuf_avail(p1), sz + r); ASSERT_SIZE_T_EQ(sshbuf_len(p1), sz2 - r); } } else if (r < 8) { /* 40% chance: big consume */ r = arc4random_uniform(2 * 1024); goto fuzz_consume; } else if (r == 8) { /* 10% chance: reset max size */ r = arc4random_uniform(16 * 1024); sz = sshbuf_max_size(p1); if (sshbuf_set_max_size(p1, r) < 0) ASSERT_SIZE_T_EQ(sshbuf_max_size(p1), sz); else ASSERT_SIZE_T_EQ(sshbuf_max_size(p1), r); } else { if (arc4random_uniform(8192) == 0) { /* tiny chance: new buffer */ ASSERT_PTR_NE(sshbuf_ptr(p1), NULL); ASSERT_MEM_ZERO_NE(sshbuf_ptr(p1), sshbuf_len(p1)); sshbuf_free(p1); p1 = sshbuf_new(); ASSERT_PTR_NE(p1, NULL); ASSERT_INT_EQ(sshbuf_set_max_size(p1, 16 * 1024), 0); } else { /* Almost 10%: giant reserve */ /* use arc4random_buf for r > 2^32 on 64 bit */ arc4random_buf(&r, sizeof(r)); while (r < SSHBUF_SIZE_MAX / 2) { r <<= 1; r |= arc4random() & 1; } goto fuzz_reserve; } } ASSERT_PTR_NE(sshbuf_ptr(p1), NULL); ASSERT_SIZE_T_LE(sshbuf_max_size(p1), 16 * 1024); } ASSERT_PTR_NE(sshbuf_ptr(p1), NULL); ASSERT_MEM_ZERO_NE(sshbuf_ptr(p1), sshbuf_len(p1)); sshbuf_free(p1); TEST_DONE(); }