static int openssh_RSA_verify(int type, u_char *hash, u_int hashlen, u_char *sigbuf, u_int siglen, RSA *rsa) { u_int ret, rsasize, oidlen = 0, hlen = 0; int len, oidmatch, hashmatch; const u_char *oid = NULL; u_char *decrypted = NULL; ret = 0; switch (type) { case NID_sha1: oid = id_sha1; oidlen = sizeof(id_sha1); hlen = 20; break; case NID_md5: oid = id_md5; oidlen = sizeof(id_md5); hlen = 16; break; default: goto done; } if (hashlen != hlen) { error("bad hashlen"); goto done; } rsasize = RSA_size(rsa); if (siglen == 0 || siglen > rsasize) { error("bad siglen"); goto done; } decrypted = xmalloc(rsasize); if ((len = RSA_public_decrypt(siglen, sigbuf, decrypted, rsa, RSA_PKCS1_PADDING)) < 0) { error("RSA_public_decrypt failed: %s", ERR_error_string(ERR_get_error(), NULL)); goto done; } if (len < 0 || (u_int)len != hlen + oidlen) { error("bad decrypted len: %d != %d + %d", len, hlen, oidlen); goto done; } oidmatch = timingsafe_bcmp(decrypted, oid, oidlen) == 0; hashmatch = timingsafe_bcmp(decrypted + oidlen, hash, hlen) == 0; if (!oidmatch) { error("oid mismatch"); goto done; } if (!hashmatch) { error("hash mismatch"); goto done; } ret = 1; done: if (decrypted) xfree(decrypted); return ret; }
static int monitor_valid_userblob(u_char *data, u_int datalen) { Buffer b; u_char *p; char *userstyle, *cp; u_int len; int fail = 0; buffer_init(&b); buffer_append(&b, data, datalen); if (datafellows & SSH_OLD_SESSIONID) { p = buffer_ptr(&b); len = buffer_len(&b); if ((session_id2 == NULL) || (len < session_id2_len) || (timingsafe_bcmp(p, session_id2, session_id2_len) != 0)) fail++; buffer_consume(&b, session_id2_len); } else { p = buffer_get_string(&b, &len); if ((session_id2 == NULL) || (len != session_id2_len) || (timingsafe_bcmp(p, session_id2, session_id2_len) != 0)) fail++; free(p); } if (buffer_get_char(&b) != SSH2_MSG_USERAUTH_REQUEST) fail++; cp = buffer_get_cstring(&b, NULL); xasprintf(&userstyle, "%s%s%s", authctxt->user, authctxt->style ? ":" : "", authctxt->style ? authctxt->style : ""); if (strcmp(userstyle, cp) != 0) { logit("wrong user name passed to monitor: " "expected %s != %.100s", userstyle, cp); fail++; } free(userstyle); free(cp); buffer_skip_string(&b); if (datafellows & SSH_BUG_PKAUTH) { if (!buffer_get_char(&b)) fail++; } else { cp = buffer_get_cstring(&b, NULL); if (strcmp("publickey", cp) != 0) fail++; free(cp); if (!buffer_get_char(&b)) fail++; buffer_skip_string(&b); } buffer_skip_string(&b); if (buffer_len(&b) != 0) fail++; buffer_free(&b); return (fail == 0); }
static int openssh_RSA_verify(int hash_alg, u_char *hash, size_t hashlen, u_char *sigbuf, size_t siglen, RSA *rsa) { size_t ret, rsasize = 0, oidlen = 0, hlen = 0; int len, oidmatch, hashmatch; const u_char *oid = NULL; u_char *decrypted = NULL; ret = SSH_ERR_INTERNAL_ERROR; switch (hash_alg) { case SSH_DIGEST_SHA1: oid = id_sha1; oidlen = sizeof(id_sha1); hlen = 20; break; default: goto done; } if (hashlen != hlen) { ret = SSH_ERR_INVALID_ARGUMENT; goto done; } rsasize = RSA_size(rsa); if (rsasize <= 0 || rsasize > SSHBUF_MAX_BIGNUM || siglen == 0 || siglen > rsasize) { ret = SSH_ERR_INVALID_ARGUMENT; goto done; } if ((decrypted = malloc(rsasize)) == NULL) { ret = SSH_ERR_ALLOC_FAIL; goto done; } if ((len = RSA_public_decrypt(siglen, sigbuf, decrypted, rsa, RSA_PKCS1_PADDING)) < 0) { ret = SSH_ERR_LIBCRYPTO_ERROR; goto done; } if (len < 0 || (size_t)len != hlen + oidlen) { ret = SSH_ERR_INVALID_FORMAT; goto done; } oidmatch = timingsafe_bcmp(decrypted, oid, oidlen) == 0; hashmatch = timingsafe_bcmp(decrypted + oidlen, hash, hlen) == 0; if (!oidmatch || !hashmatch) { ret = SSH_ERR_SIGNATURE_INVALID; goto done; } ret = 0; done: if (decrypted) { explicit_bzero(decrypted, rsasize); free(decrypted); } return ret; }
static int openssh_RSA_verify(int hash_alg, u_char *hash, size_t hashlen, u_char *sigbuf, size_t siglen, RSA *rsa) { size_t rsasize = 0, oidlen = 0, hlen = 0; int ret, len, oidmatch, hashmatch; const u_char *oid = NULL; u_char *decrypted = NULL; if ((ret = rsa_hash_alg_oid(hash_alg, &oid, &oidlen)) != 0) return ret; ret = SSH_ERR_INTERNAL_ERROR; hlen = ssh_digest_bytes(hash_alg); if (hashlen != hlen) { ret = SSH_ERR_INVALID_ARGUMENT; goto done; } rsasize = RSA_size(rsa); if (rsasize <= 0 || rsasize > SSHBUF_MAX_BIGNUM || siglen == 0 || siglen > rsasize) { ret = SSH_ERR_INVALID_ARGUMENT; goto done; } if ((decrypted = malloc(rsasize)) == NULL) { ret = SSH_ERR_ALLOC_FAIL; goto done; } if ((len = RSA_public_decrypt(siglen, sigbuf, decrypted, rsa, RSA_PKCS1_PADDING)) < 0) { ret = SSH_ERR_LIBCRYPTO_ERROR; goto done; } if (len < 0 || (size_t)len != hlen + oidlen) { ret = SSH_ERR_INVALID_FORMAT; goto done; } oidmatch = timingsafe_bcmp(decrypted, oid, oidlen) == 0; hashmatch = timingsafe_bcmp(decrypted + oidlen, hash, hlen) == 0; if (!oidmatch || !hashmatch) { ret = SSH_ERR_SIGNATURE_INVALID; goto done; } ret = 0; done: if (decrypted) { explicit_bzero(decrypted, rsasize); free(decrypted); } return ret; }
int crypt_checkpass(const char *pass, const char *goodhash) { char dummy[_PASSWORD_LEN]; char *res; if (goodhash == NULL) { /* fake it */ bcrypt_newhash(pass, 8, dummy, sizeof(dummy)); goto fail; } /* empty password */ if (strlen(goodhash) == 0 && strlen(pass) == 0) return 0; if (goodhash[0] == '$' && goodhash[1] == '2') { return bcrypt_checkpass(pass, goodhash); } /* have to do it the hard way */ res = crypt(pass, goodhash); if (strlen(res) != strlen(goodhash) || timingsafe_bcmp(res, goodhash, strlen(goodhash)) != 0) { goto fail; } return 0; fail: errno = EACCES; return -1; }
int aes_key_unwrap(aes_key_wrap_ctx *ctx, const u_int8_t *C, u_int8_t *P, size_t n) { u_int64_t B[2], t; u_int8_t A[8], *R; size_t i; int j; memcpy(A, C, 8); /* A = C[0] */ memmove(P, C + 8, n * 8); /* P and C may overlap */ for (j = 5, t = 6 * n; j >= 0; j--) { R = P + (n - 1) * 8; for (i = n; i >= 1; i--, t--) { /* MSB(64, B) = A */ memcpy(&B[0], A, 8); /* MSB(64, B) = MSB(64, B) ^ t */ B[0] ^= htobe64(t); /* B = MSB(64, B) | R[i] */ memcpy(&B[1], R, 8); /* B = AES-1(K, B) */ rijndael_decrypt(&ctx->ctx, (caddr_t)B, (caddr_t)B); /* A = MSB(64, B) */ memcpy(A, &B[0], 8); /* R[i] = LSB(64, B) */ memcpy(R, &B[1], 8); R -= 8; } } explicit_bzero(B, sizeof B); /* check that A is an appropriate initial value */ return timingsafe_bcmp(A, IV, 8) != 0; }
/* * Calculate and check confirmation hash from peer. Returns 1 on success * 0 on failure/mismatch. */ int jpake_check_confirm(const BIGNUM *k, const u_char *peer_id, u_int peer_id_len, const u_char *sess_id, u_int sess_id_len, const u_char *peer_confirm_hash, u_int peer_confirm_hash_len) { u_char *expected_confirm_hash; u_int expected_confirm_hash_len; int success = 0; /* Calculate and verify expected confirmation hash */ jpake_confirm_hash(k, peer_id, peer_id_len, sess_id, sess_id_len, &expected_confirm_hash, &expected_confirm_hash_len); JPAKE_DEBUG_BUF((expected_confirm_hash, expected_confirm_hash_len, "%s: expected confirm hash", __func__)); JPAKE_DEBUG_BUF((peer_confirm_hash, peer_confirm_hash_len, "%s: received confirm hash", __func__)); if (peer_confirm_hash_len != expected_confirm_hash_len) error("%s: confirmation length mismatch (my %u them %u)", __func__, expected_confirm_hash_len, peer_confirm_hash_len); else if (timingsafe_bcmp(peer_confirm_hash, expected_confirm_hash, expected_confirm_hash_len) == 0) success = 1; bzero(expected_confirm_hash, expected_confirm_hash_len); xfree(expected_confirm_hash); debug3("%s: success = %d", __func__, success); return success; }
int kexc25519_shared_key_ext(const u_char key[CURVE25519_SIZE], const u_char pub[CURVE25519_SIZE], struct sshbuf *out, int raw) { u_char shared_key[CURVE25519_SIZE]; u_char zero[CURVE25519_SIZE]; int r; crypto_scalarmult_curve25519(shared_key, key, pub); /* Check for all-zero shared secret */ explicit_bzero(zero, CURVE25519_SIZE); if (timingsafe_bcmp(zero, shared_key, CURVE25519_SIZE) == 0) return SSH_ERR_KEY_INVALID_EC_VALUE; #ifdef DEBUG_KEXECDH dump_digest("shared secret", shared_key, CURVE25519_SIZE); #endif if (raw) r = sshbuf_put(out, shared_key, CURVE25519_SIZE); else r = sshbuf_put_bignum2_bytes(out, shared_key, CURVE25519_SIZE); explicit_bzero(shared_key, CURVE25519_SIZE); return r; }
int auth_rsa_verify_response(struct sshkey *key, BIGNUM *challenge, u_char response[16]) { u_char buf[32], mdbuf[16]; MD5_CTX md; int len; /* don't allow short keys */ if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) { error("auth_rsa_verify_response: RSA modulus too small: %d < minimum %d bits", BN_num_bits(key->rsa->n), SSH_RSA_MINIMUM_MODULUS_SIZE); return (0); } /* The response is MD5 of decrypted challenge plus session id. */ len = BN_num_bytes(challenge); if (len <= 0 || len > 32) fatal("auth_rsa_verify_response: bad challenge length %d", len); memset(buf, 0, 32); BN_bn2bin(challenge, buf + 32 - len); MD5_Init(&md); MD5_Update(&md, buf, 32); MD5_Update(&md, session_id, 16); MD5_Final(mdbuf, &md); /* Verify that the response is the original challenge. */ if (timingsafe_bcmp(response, mdbuf, 16) != 0) { /* Wrong answer. */ return (0); } /* Correct answer. */ return (1); }
int kexc25519_shared_key(const u_char key[CURVE25519_SIZE], const u_char pub[CURVE25519_SIZE], struct sshbuf *out) { u_char shared_key[CURVE25519_SIZE]; int r; #ifdef USING_WOLFSSL int ret, ssize = CURVE25519_SIZE; ret = wolfSSL_EC25519_shared_key(shared_key, &ssize, key, CURVE25519_SIZE, pub, CURVE25519_SIZE); if (ret != 1 || ssize != CURVE25519_SIZE) fatal("%s: wolfSSL_EC25519_shared_key failed", __func__); #else /* Check for all-zero public key */ explicit_bzero(shared_key, CURVE25519_SIZE); if (timingsafe_bcmp(pub, shared_key, CURVE25519_SIZE) == 0) return SSH_ERR_KEY_INVALID_EC_VALUE; crypto_scalarmult_curve25519(shared_key, key, pub); #endif /* USING_WOLFSSL */ #ifdef DEBUG_KEXECDH dump_digest("shared secret", shared_key, CURVE25519_SIZE); #endif sshbuf_reset(out); r = sshbuf_put_bignum2_bytes(out, shared_key, CURVE25519_SIZE); explicit_bzero(shared_key, CURVE25519_SIZE); return r; }
static int monitor_valid_hostbasedblob(u_char *data, u_int datalen, char *cuser, char *chost) { Buffer b; char *p, *userstyle; u_int len; int fail = 0; buffer_init(&b); buffer_append(&b, data, datalen); p = buffer_get_string(&b, &len); if ((session_id2 == NULL) || (len != session_id2_len) || (timingsafe_bcmp(p, session_id2, session_id2_len) != 0)) fail++; free(p); if (buffer_get_char(&b) != SSH2_MSG_USERAUTH_REQUEST) fail++; p = buffer_get_cstring(&b, NULL); xasprintf(&userstyle, "%s%s%s", authctxt->user, authctxt->style ? ":" : "", authctxt->style ? authctxt->style : ""); if (strcmp(userstyle, p) != 0) { logit("wrong user name passed to monitor: expected %s != %.100s", userstyle, p); fail++; } free(userstyle); free(p); buffer_skip_string(&b); /* service */ p = buffer_get_cstring(&b, NULL); if (strcmp(p, "hostbased") != 0) fail++; free(p); buffer_skip_string(&b); /* pkalg */ buffer_skip_string(&b); /* pkblob */ /* verify client host, strip trailing dot if necessary */ p = buffer_get_string(&b, NULL); if (((len = strlen(p)) > 0) && p[len - 1] == '.') p[len - 1] = '\0'; if (strcmp(p, chost) != 0) fail++; free(p); /* verify client user */ p = buffer_get_string(&b, NULL); if (strcmp(p, cuser) != 0) fail++; free(p); if (buffer_len(&b) != 0) fail++; buffer_free(&b); return (fail == 0); }
int test_bcmp() { size_t i; struct timespec x,y; long diff[4]; memset(a,23,sizeof(a)); memset(b,23,sizeof(b)); assert(clock_gettime(CLOCK_MONOTONIC,&x)==0); for (i=0; i<100000; ++i) { assert(timingsafe_bcmp(a,b,sizeof(a))==0); } assert(clock_gettime(CLOCK_MONOTONIC,&y)==0); diff[0]=(y.tv_sec-x.tv_sec)*1000000000 + y.tv_nsec-x.tv_nsec; printf("timingsafe_bcmp: %lu.%09lu %lu.%09lu - %lu\n",x.tv_sec,x.tv_nsec,y.tv_sec,y.tv_nsec,diff[0]); assert(clock_gettime(CLOCK_MONOTONIC,&x)==0); for (i=0; i<100000; ++i) { assert(bcmp(a,b,sizeof(a))==0); } assert(clock_gettime(CLOCK_MONOTONIC,&y)==0); diff[1]=(y.tv_sec-x.tv_sec)*1000000000 + y.tv_nsec-x.tv_nsec; printf(" regular bcmp: %lu.%09lu %lu.%09lu - %lu\n",x.tv_sec,x.tv_nsec,y.tv_sec,y.tv_nsec,diff[1]); a[10]=24; // now give bcmp an opportunity to exit early assert(clock_gettime(CLOCK_MONOTONIC,&x)==0); for (i=0; i<100000; ++i) { assert(timingsafe_bcmp(a,b,sizeof(a))==1); } assert(clock_gettime(CLOCK_MONOTONIC,&y)==0); diff[2]=(y.tv_sec-x.tv_sec)*1000000000 + y.tv_nsec-x.tv_nsec; printf("timingsafe_bcmp: %lu.%09lu %lu.%09lu - %lu\n",x.tv_sec,x.tv_nsec,y.tv_sec,y.tv_nsec,diff[2]); assert(clock_gettime(CLOCK_MONOTONIC,&x)==0); for (i=0; i<100000; ++i) { assert(bcmp(a,b,sizeof(a))==1); } assert(clock_gettime(CLOCK_MONOTONIC,&y)==0); diff[3]=(y.tv_sec-x.tv_sec)*1000000000 + y.tv_nsec-x.tv_nsec; printf(" regular bcmp: %lu.%09lu %lu.%09lu - %lu\n",x.tv_sec,x.tv_nsec,y.tv_sec,y.tv_nsec,diff[3]); /* we expect the timingsafe_bcmp values to be roughly the same (+- 10% for measurement inaccuracies) */ long delta=diff[0]-diff[2]; if (delta<0) delta=-delta; assert(delta*10<diff[0]); }
/* allowed key state */ static int monitor_allowed_key(u_char *blob, u_int bloblen) { /* make sure key is allowed */ if (key_blob == NULL || key_bloblen != bloblen || timingsafe_bcmp(key_blob, blob, key_bloblen)) return (0); return (1); }
/* * chachapoly_crypt() operates as following: * En/decrypt with header key 'aadlen' bytes from 'src', storing result * to 'dest'. The ciphertext here is treated as additional authenticated * data for MAC calculation. * En/decrypt 'len' bytes at offset 'aadlen' from 'src' to 'dest'. Use * POLY1305_TAGLEN bytes at offset 'len'+'aadlen' as the authentication * tag. This tag is written on encryption and verified on decryption. */ int chachapoly_crypt(struct chachapoly_ctx *ctx, u_int seqnr, u_char *dest, const u_char *src, u_int len, u_int aadlen, u_int authlen, int do_encrypt) { u_char seqbuf[8]; const u_char one[8] = { 1, 0, 0, 0, 0, 0, 0, 0 }; /* NB little-endian */ u_char expected_tag[POLY1305_TAGLEN], poly_key[POLY1305_KEYLEN]; int r = SSH_ERR_INTERNAL_ERROR; /* * Run ChaCha20 once to generate the Poly1305 key. The IV is the * packet sequence number. */ memset(poly_key, 0, sizeof(poly_key)); POKE_U64(seqbuf, seqnr); chacha_ivsetup(&ctx->main_ctx, seqbuf, NULL); chacha_encrypt_bytes(&ctx->main_ctx, poly_key, poly_key, sizeof(poly_key)); /* If decrypting, check tag before anything else */ if (!do_encrypt) { const u_char *tag = src + aadlen + len; poly1305_auth(expected_tag, src, aadlen + len, poly_key); if (timingsafe_bcmp(expected_tag, tag, POLY1305_TAGLEN) != 0) { r = SSH_ERR_MAC_INVALID; goto out; } } /* Crypt additional data */ if (aadlen) { chacha_ivsetup(&ctx->header_ctx, seqbuf, NULL); chacha_encrypt_bytes(&ctx->header_ctx, src, dest, aadlen); } /* Set Chacha's block counter to 1 */ chacha_ivsetup(&ctx->main_ctx, seqbuf, one); chacha_encrypt_bytes(&ctx->main_ctx, src + aadlen, dest + aadlen, len); /* If encrypting, calculate and append tag */ if (do_encrypt) { poly1305_auth(dest + aadlen + len, dest, aadlen + len, poly_key); } r = 0; out: explicit_bzero(expected_tag, sizeof(expected_tag)); explicit_bzero(seqbuf, sizeof(seqbuf)); explicit_bzero(poly_key, sizeof(poly_key)); return r; }
int kexc25519_shared_key(const u_char key[CURVE25519_SIZE], const u_char pub[CURVE25519_SIZE], struct sshbuf *out) { u_char shared_key[CURVE25519_SIZE]; int r; /* Check for all-zero public key */ explicit_bzero(shared_key, CURVE25519_SIZE); if (timingsafe_bcmp(pub, shared_key, CURVE25519_SIZE) == 0) return SSH_ERR_KEY_INVALID_EC_VALUE; crypto_scalarmult_curve25519(shared_key, key, pub); #ifdef DEBUG_KEXECDH dump_digest("shared secret", shared_key, CURVE25519_SIZE); #endif sshbuf_reset(out); r = sshbuf_put_bignum2_bytes(out, shared_key, CURVE25519_SIZE); explicit_bzero(shared_key, CURVE25519_SIZE); return r; }
/* * ESP input callback from the crypto driver. */ static int esp_input_cb(struct cryptop *crp) { IPSEC_DEBUG_DECLARE(char buf[128]); u_int8_t lastthree[3], aalg[AH_HMAC_MAXHASHLEN]; const struct auth_hash *esph; const struct enc_xform *espx; struct mbuf *m; struct cryptodesc *crd; struct xform_data *xd; struct secasvar *sav; struct secasindex *saidx; caddr_t ptr; uint64_t cryptoid; int hlen, skip, protoff, error, alen; crd = crp->crp_desc; IPSEC_ASSERT(crd != NULL, ("null crypto descriptor!")); m = (struct mbuf *) crp->crp_buf; xd = (struct xform_data *) crp->crp_opaque; sav = xd->sav; skip = xd->skip; protoff = xd->protoff; cryptoid = xd->cryptoid; saidx = &sav->sah->saidx; esph = sav->tdb_authalgxform; espx = sav->tdb_encalgxform; /* Check for crypto errors */ if (crp->crp_etype) { if (crp->crp_etype == EAGAIN) { /* Reset the session ID */ if (ipsec_updateid(sav, &crp->crp_sid, &cryptoid) != 0) crypto_freesession(cryptoid); xd->cryptoid = crp->crp_sid; return (crypto_dispatch(crp)); } ESPSTAT_INC(esps_noxform); DPRINTF(("%s: crypto error %d\n", __func__, crp->crp_etype)); error = crp->crp_etype; goto bad; } /* Shouldn't happen... */ if (m == NULL) { ESPSTAT_INC(esps_crypto); DPRINTF(("%s: bogus returned buffer from crypto\n", __func__)); error = EINVAL; goto bad; } ESPSTAT_INC(esps_hist[sav->alg_enc]); /* If authentication was performed, check now. */ if (esph != NULL) { alen = xform_ah_authsize(esph); AHSTAT_INC(ahs_hist[sav->alg_auth]); /* Copy the authenticator from the packet */ m_copydata(m, m->m_pkthdr.len - alen, alen, aalg); ptr = (caddr_t) (xd + 1); /* Verify authenticator */ if (timingsafe_bcmp(ptr, aalg, alen) != 0) { DPRINTF(("%s: authentication hash mismatch for " "packet in SA %s/%08lx\n", __func__, ipsec_address(&saidx->dst, buf, sizeof(buf)), (u_long) ntohl(sav->spi))); ESPSTAT_INC(esps_badauth); error = EACCES; goto bad; } m->m_flags |= M_AUTHIPDGM; /* Remove trailing authenticator */ m_adj(m, -alen); } /* Release the crypto descriptors */ free(xd, M_XDATA), xd = NULL; crypto_freereq(crp), crp = NULL; /* * Packet is now decrypted. */ m->m_flags |= M_DECRYPTED; /* * Update replay sequence number, if appropriate. */ if (sav->replay) { u_int32_t seq; m_copydata(m, skip + offsetof(struct newesp, esp_seq), sizeof (seq), (caddr_t) &seq); SECASVAR_LOCK(sav); if (ipsec_updatereplay(ntohl(seq), sav)) { SECASVAR_UNLOCK(sav); DPRINTF(("%s: packet replay check for %s\n", __func__, ipsec_sa2str(sav, buf, sizeof(buf)))); ESPSTAT_INC(esps_replay); error = EACCES; goto bad; } SECASVAR_UNLOCK(sav); }
/* * ESP input callback, called directly by the crypto driver. */ int esp_input_cb(void *op) { u_int8_t lastthree[3], aalg[AH_HMAC_MAX_HASHLEN]; int s, hlen, roff, skip, protoff, error; struct mbuf *m1, *mo, *m; struct auth_hash *esph; struct tdb_crypto *tc; struct cryptop *crp; struct m_tag *mtag; struct tdb *tdb; u_int32_t btsx; caddr_t ptr; crp = (struct cryptop *) op; tc = (struct tdb_crypto *) crp->crp_opaque; skip = tc->tc_skip; protoff = tc->tc_protoff; mtag = (struct m_tag *) tc->tc_ptr; m = (struct mbuf *) crp->crp_buf; if (m == NULL) { /* Shouldn't happen... */ free(tc, M_XDATA); crypto_freereq(crp); espstat.esps_crypto++; DPRINTF(("esp_input_cb(): bogus returned buffer from crypto\n")); return (EINVAL); } s = spltdb(); tdb = gettdb(tc->tc_rdomain, tc->tc_spi, &tc->tc_dst, tc->tc_proto); if (tdb == NULL) { free(tc, M_XDATA); espstat.esps_notdb++; DPRINTF(("esp_input_cb(): TDB is expired while in crypto")); error = EPERM; goto baddone; } esph = (struct auth_hash *) tdb->tdb_authalgxform; /* Check for crypto errors */ if (crp->crp_etype) { if (crp->crp_etype == EAGAIN) { /* Reset the session ID */ if (tdb->tdb_cryptoid != 0) tdb->tdb_cryptoid = crp->crp_sid; splx(s); return crypto_dispatch(crp); } free(tc, M_XDATA); espstat.esps_noxform++; DPRINTF(("esp_input_cb(): crypto error %d\n", crp->crp_etype)); error = crp->crp_etype; goto baddone; } /* If authentication was performed, check now. */ if (esph != NULL) { /* * If we have a tag, it means an IPsec-aware NIC did the verification * for us. */ if (mtag == NULL) { /* Copy the authenticator from the packet */ m_copydata(m, m->m_pkthdr.len - esph->authsize, esph->authsize, aalg); ptr = (caddr_t) (tc + 1); /* Verify authenticator */ if (timingsafe_bcmp(ptr, aalg, esph->authsize)) { free(tc, M_XDATA); DPRINTF(("esp_input_cb(): authentication failed for packet in SA %s/%08x\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); espstat.esps_badauth++; error = EACCES; goto baddone; } } /* Remove trailing authenticator */ m_adj(m, -(esph->authsize)); } free(tc, M_XDATA); /* Replay window checking, if appropriate */ if ((tdb->tdb_wnd > 0) && (!(tdb->tdb_flags & TDBF_NOREPLAY))) { m_copydata(m, skip + sizeof(u_int32_t), sizeof(u_int32_t), (unsigned char *) &btsx); btsx = ntohl(btsx); switch (checkreplaywindow32(btsx, 0, &(tdb->tdb_rpl), tdb->tdb_wnd, &(tdb->tdb_bitmap), 1)) { case 0: /* All's well */ #if NPFSYNC > 0 pfsync_update_tdb(tdb,0); #endif break; case 1: DPRINTF(("esp_input_cb(): replay counter wrapped for SA %s/%08x\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); espstat.esps_wrap++; error = EACCES; goto baddone; case 2: case 3: DPRINTF(("esp_input_cb(): duplicate packet received in SA %s/%08x\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); error = EACCES; goto baddone; default: DPRINTF(("esp_input_cb(): bogus value from checkreplaywindow32() in SA %s/%08x\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); espstat.esps_replay++; error = EACCES; goto baddone; } } /* Release the crypto descriptors */ crypto_freereq(crp); /* Determine the ESP header length */ if (tdb->tdb_flags & TDBF_NOREPLAY) hlen = sizeof(u_int32_t) + tdb->tdb_ivlen; /* "old" ESP */ else hlen = 2 * sizeof(u_int32_t) + tdb->tdb_ivlen; /* "new" ESP */ /* Find beginning of ESP header */ m1 = m_getptr(m, skip, &roff); if (m1 == NULL) { espstat.esps_hdrops++; splx(s); DPRINTF(("esp_input_cb(): bad mbuf chain, SA %s/%08x\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); m_freem(m); return EINVAL; } /* Remove the ESP header and IV from the mbuf. */ if (roff == 0) { /* The ESP header was conveniently at the beginning of the mbuf */ m_adj(m1, hlen); if (!(m1->m_flags & M_PKTHDR)) m->m_pkthdr.len -= hlen; } else if (roff + hlen >= m1->m_len) { /* * Part or all of the ESP header is at the end of this mbuf, so * first let's remove the remainder of the ESP header from the * beginning of the remainder of the mbuf chain, if any. */ if (roff + hlen > m1->m_len) { /* Adjust the next mbuf by the remainder */ m_adj(m1->m_next, roff + hlen - m1->m_len); /* The second mbuf is guaranteed not to have a pkthdr... */ m->m_pkthdr.len -= (roff + hlen - m1->m_len); } /* Now, let's unlink the mbuf chain for a second...*/ mo = m1->m_next; m1->m_next = NULL; /* ...and trim the end of the first part of the chain...sick */ m_adj(m1, -(m1->m_len - roff)); if (!(m1->m_flags & M_PKTHDR)) m->m_pkthdr.len -= (m1->m_len - roff); /* Finally, let's relink */ m1->m_next = mo; } else { /* * The ESP header lies in the "middle" of the mbuf...do an * overlapping copy of the remainder of the mbuf over the ESP * header. */ bcopy(mtod(m1, u_char *) + roff + hlen, mtod(m1, u_char *) + roff, m1->m_len - (roff + hlen)); m1->m_len -= hlen; m->m_pkthdr.len -= hlen; } /* Save the last three bytes of decrypted data */ m_copydata(m, m->m_pkthdr.len - 3, 3, lastthree); /* Verify pad length */ if (lastthree[1] + 2 > m->m_pkthdr.len - skip) { espstat.esps_badilen++; splx(s); DPRINTF(("esp_input_cb(): invalid padding length %d for packet in SA %s/%08x\n", lastthree[1], ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); m_freem(m); return EINVAL; } /* Verify correct decryption by checking the last padding bytes */ if (!(tdb->tdb_flags & TDBF_RANDOMPADDING)) { if ((lastthree[1] != lastthree[0]) && (lastthree[1] != 0)) { espstat.esps_badenc++; splx(s); DPRINTF(("esp_input(): decryption failed for packet in SA %s/%08x\n", ipsp_address(tdb->tdb_dst), ntohl(tdb->tdb_spi))); m_freem(m); return EINVAL; } } /* Trim the mbuf chain to remove the trailing authenticator and padding */ m_adj(m, -(lastthree[1] + 2)); /* Restore the Next Protocol field */ m_copyback(m, protoff, sizeof(u_int8_t), lastthree + 2, M_NOWAIT); /* Back to generic IPsec input processing */ error = ipsec_common_input_cb(m, tdb, skip, protoff, mtag); splx(s); return (error); baddone: splx(s); if (m != NULL) m_freem(m); crypto_freereq(crp); return (error); }
/* * ESP input callback from the crypto driver. */ static int esp_input_cb(struct cryptop *crp) { char buf[128]; u_int8_t lastthree[3], aalg[AH_HMAC_MAXHASHLEN]; int hlen, skip, protoff, error, alen; struct mbuf *m; struct cryptodesc *crd; struct auth_hash *esph; struct enc_xform *espx; struct tdb_crypto *tc; struct secasvar *sav; struct secasindex *saidx; caddr_t ptr; crd = crp->crp_desc; IPSEC_ASSERT(crd != NULL, ("null crypto descriptor!")); tc = (struct tdb_crypto *) crp->crp_opaque; IPSEC_ASSERT(tc != NULL, ("null opaque crypto data area!")); skip = tc->tc_skip; protoff = tc->tc_protoff; m = (struct mbuf *) crp->crp_buf; sav = tc->tc_sav; IPSEC_ASSERT(sav != NULL, ("null SA!")); saidx = &sav->sah->saidx; IPSEC_ASSERT(saidx->dst.sa.sa_family == AF_INET || saidx->dst.sa.sa_family == AF_INET6, ("unexpected protocol family %u", saidx->dst.sa.sa_family)); esph = sav->tdb_authalgxform; espx = sav->tdb_encalgxform; /* Check for crypto errors */ if (crp->crp_etype) { /* Reset the session ID */ if (sav->tdb_cryptoid != 0) sav->tdb_cryptoid = crp->crp_sid; if (crp->crp_etype == EAGAIN) return (crypto_dispatch(crp)); ESPSTAT_INC(esps_noxform); DPRINTF(("%s: crypto error %d\n", __func__, crp->crp_etype)); error = crp->crp_etype; goto bad; } /* Shouldn't happen... */ if (m == NULL) { ESPSTAT_INC(esps_crypto); DPRINTF(("%s: bogus returned buffer from crypto\n", __func__)); error = EINVAL; goto bad; } ESPSTAT_INC(esps_hist[sav->alg_enc]); /* If authentication was performed, check now. */ if (esph != NULL) { alen = xform_ah_authsize(esph); AHSTAT_INC(ahs_hist[sav->alg_auth]); /* Copy the authenticator from the packet */ m_copydata(m, m->m_pkthdr.len - alen, alen, aalg); ptr = (caddr_t) (tc + 1); /* Verify authenticator */ if (timingsafe_bcmp(ptr, aalg, alen) != 0) { DPRINTF(("%s: authentication hash mismatch for " "packet in SA %s/%08lx\n", __func__, ipsec_address(&saidx->dst, buf, sizeof(buf)), (u_long) ntohl(sav->spi))); ESPSTAT_INC(esps_badauth); error = EACCES; goto bad; } /* Remove trailing authenticator */ m_adj(m, -alen); } /* Release the crypto descriptors */ free(tc, M_XDATA), tc = NULL; crypto_freereq(crp), crp = NULL; /* * Packet is now decrypted. */ m->m_flags |= M_DECRYPTED; /* * Update replay sequence number, if appropriate. */ if (sav->replay) { u_int32_t seq; m_copydata(m, skip + offsetof(struct newesp, esp_seq), sizeof (seq), (caddr_t) &seq); if (ipsec_updatereplay(ntohl(seq), sav)) { DPRINTF(("%s: packet replay check for %s\n", __func__, ipsec_logsastr(sav, buf, sizeof(buf)))); ESPSTAT_INC(esps_replay); error = ENOBUFS; goto bad; } }
static int monitor_valid_hostbasedblob(u_char *data, u_int datalen, char *cuser, char *chost) { struct sshbuf *b; char *username, *methodname, *rawhost, *ruser, *userstyle; u_char *sid, c; size_t len; int r, fail = 0; if ((b = sshbuf_from(data, datalen)) == NULL) fatal("%s: sshbuf_from failed", __func__); if ((r = sshbuf_get_string(b, &sid, &len)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); if ((session_id2 == NULL) || (len != session_id2_len) || (timingsafe_bcmp(sid, session_id2, session_id2_len) != 0)) fail++; free(sid); if ((r = sshbuf_get_u8(b, &c)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); if (c != SSH2_MSG_USERAUTH_REQUEST) fail++; if ((r = sshbuf_get_cstring(b, &username, NULL)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); xasprintf(&userstyle, "%s%s%s", authctxt->user, authctxt->style ? ":" : "", authctxt->style ? authctxt->style : ""); if (strcmp(userstyle, username) != 0) { logit("wrong user name sent to monitor: expected %s != %.100s", userstyle, username); fail++; } free(userstyle); free(username); if ((r = sshbuf_skip_string(b)) != 0 || /* service */ (r = sshbuf_get_cstring(b, &methodname, NULL)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); if (strcmp("hostbased", methodname) != 0) fail++; free(methodname); if ((r = sshbuf_skip_string(b)) != 0 || /* pkalg */ (r = sshbuf_skip_string(b)) != 0) /* pkblob */ fatal("%s: buffer error: %s", __func__, ssh_err(r)); /* verify client host, strip trailing dot if necessary */ if ((r = sshbuf_get_cstring(b, &rawhost, NULL)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); if (((len = strlen(rawhost)) > 0) && rawhost[len - 1] == '.') rawhost[len - 1] = '\0'; if (strcmp(rawhost, chost) != 0) fail++; free(rawhost); /* verify client user */ if ((r = sshbuf_get_cstring(b, &ruser, NULL)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); if (strcmp(ruser, cuser) != 0) fail++; free(ruser); if (sshbuf_len(b) != 0) fail++; sshbuf_free(b); return (fail == 0); }
static int monitor_valid_userblob(u_char *data, u_int datalen) { struct sshbuf *b; u_char *p, c; const u_char *cp; size_t len; int r, fail = 0; char *username, *methodname, *userstyle; if ((b = sshbuf_from(data, datalen)) == NULL) fatal("%s: sshbuf_from failed", __func__); if (active_state->compat & SSH_OLD_SESSIONID) { cp = sshbuf_ptr(b); len = sshbuf_len(b); if ((session_id2 == NULL) || (len < session_id2_len) || (timingsafe_bcmp(cp, session_id2, session_id2_len) != 0)) fail++; if ((r = sshbuf_consume(b, session_id2_len)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); } else { if ((r = sshbuf_get_string(b, &p, &len)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); if ((session_id2 == NULL) || (len != session_id2_len) || (timingsafe_bcmp(p, session_id2, session_id2_len) != 0)) fail++; free(p); } if ((r = sshbuf_get_u8(b, &c)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); if (c != SSH2_MSG_USERAUTH_REQUEST) fail++; xasprintf(&userstyle, "%s%s%s", authctxt->user, authctxt->style ? ":" : "", authctxt->style ? authctxt->style : ""); if ((r = sshbuf_get_cstring(b, &username, NULL)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); if (strcmp(userstyle, username) != 0) { logit("wrong user name sent to monitor: expected %s != %.100s", userstyle, username); fail++; } free(username); free(userstyle); if ((r = sshbuf_skip_string(b)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); if (active_state->compat & SSH_BUG_PKAUTH) { if ((r = sshbuf_get_u8(b, &c)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); if (!c) fail++; } else { if ((r = sshbuf_get_cstring(b, &methodname, NULL)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); if (strcmp("publickey", methodname) != 0) fail++; free(methodname); if ((r = sshbuf_get_u8(b, &c)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); if (!c) fail++; if ((r = sshbuf_skip_string(b)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); } if ((r = sshbuf_skip_string(b)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); if (sshbuf_len(b) != 0) fail++; sshbuf_free(b); return (fail == 0); }
int crypto_verify_32(const unsigned char *x, const unsigned char *y) { return timingsafe_bcmp(x, y, 32) ? -1 : 0; }
/* * Verify the given hostname, address and host key using DNS. * Returns 0 if lookup succeeds, -1 otherwise */ int verify_host_key_dns(const char *hostname, struct sockaddr *address, struct sshkey *hostkey, int *flags) { u_int counter; int result; unsigned int rrset_flags = 0; struct rrsetinfo *fingerprints = NULL; u_int8_t hostkey_algorithm; u_int8_t hostkey_digest_type = SSHFP_HASH_RESERVED; u_char *hostkey_digest; size_t hostkey_digest_len; u_int8_t dnskey_algorithm; u_int8_t dnskey_digest_type; u_char *dnskey_digest; size_t dnskey_digest_len; *flags = 0; debug3("verify_host_key_dns"); if (hostkey == NULL) fatal("No key to look up!"); if (is_numeric_hostname(hostname)) { debug("skipped DNS lookup for numerical hostname"); return -1; } /* * Original getrrsetbyname function, found on OpenBSD for example, * doesn't accept any flag and prerequisite for obtaining AD bit in * DNS response is set by "options edns0" in resolv.conf. * * Our version is more clever and use RRSET_FORCE_EDNS0 flag. */ #ifndef HAVE_GETRRSETBYNAME rrset_flags |= RRSET_FORCE_EDNS0; #endif result = getrrsetbyname(hostname, DNS_RDATACLASS_IN, DNS_RDATATYPE_SSHFP, rrset_flags, &fingerprints); if (result) { verbose("DNS lookup error: %s", dns_result_totext(result)); return -1; } if (fingerprints->rri_flags & RRSET_VALIDATED) { *flags |= DNS_VERIFY_SECURE; debug("found %d secure fingerprints in DNS", fingerprints->rri_nrdatas); } else { debug("found %d insecure fingerprints in DNS", fingerprints->rri_nrdatas); } /* Initialize default host key parameters */ if (!dns_read_key(&hostkey_algorithm, &hostkey_digest_type, &hostkey_digest, &hostkey_digest_len, hostkey)) { error("Error calculating host key fingerprint."); freerrset(fingerprints); return -1; } if (fingerprints->rri_nrdatas) *flags |= DNS_VERIFY_FOUND; for (counter = 0; counter < fingerprints->rri_nrdatas; counter++) { /* * Extract the key from the answer. Ignore any badly * formatted fingerprints. */ if (!dns_read_rdata(&dnskey_algorithm, &dnskey_digest_type, &dnskey_digest, &dnskey_digest_len, fingerprints->rri_rdatas[counter].rdi_data, fingerprints->rri_rdatas[counter].rdi_length)) { verbose("Error parsing fingerprint from DNS."); continue; } if (hostkey_digest_type != dnskey_digest_type) { hostkey_digest_type = dnskey_digest_type; free(hostkey_digest); /* Initialize host key parameters */ if (!dns_read_key(&hostkey_algorithm, &hostkey_digest_type, &hostkey_digest, &hostkey_digest_len, hostkey)) { error("Error calculating key fingerprint."); freerrset(fingerprints); return -1; } } /* Check if the current key is the same as the given key */ if (hostkey_algorithm == dnskey_algorithm && hostkey_digest_type == dnskey_digest_type) { if (hostkey_digest_len == dnskey_digest_len && timingsafe_bcmp(hostkey_digest, dnskey_digest, hostkey_digest_len) == 0) *flags |= DNS_VERIFY_MATCH; } free(dnskey_digest); } free(hostkey_digest); /* from sshkey_fingerprint_raw() */ freerrset(fingerprints); if (*flags & DNS_VERIFY_FOUND) if (*flags & DNS_VERIFY_MATCH) debug("matching host key fingerprint found in DNS"); else debug("mismatching host key fingerprint found in DNS"); else debug("no host key fingerprint found in DNS"); return 0; }
int ssl3_get_finished(SSL *s, int a, int b) { int al,i,ok; long n; unsigned char *p; #ifdef OPENSSL_NO_NEXTPROTONEG /* the mac has already been generated when we received the change * cipher spec message and is in s->s3->tmp.peer_finish_md. */ #endif n=s->method->ssl_get_message(s, a, b, SSL3_MT_FINISHED, 64, /* should actually be 36+4 :-) */ &ok); if (!ok) return((int)n); /* If this occurs, we have missed a message */ if (!s->s3->change_cipher_spec) { al=SSL_AD_UNEXPECTED_MESSAGE; SSLerr(SSL_F_SSL3_GET_FINISHED,SSL_R_GOT_A_FIN_BEFORE_A_CCS); goto f_err; } s->s3->change_cipher_spec=0; p = (unsigned char *)s->init_msg; i = s->s3->tmp.peer_finish_md_len; if (i != n) { al=SSL_AD_DECODE_ERROR; SSLerr(SSL_F_SSL3_GET_FINISHED,SSL_R_BAD_DIGEST_LENGTH); goto f_err; } if (timingsafe_bcmp(p, s->s3->tmp.peer_finish_md, i) != 0) { al=SSL_AD_DECRYPT_ERROR; SSLerr(SSL_F_SSL3_GET_FINISHED,SSL_R_DIGEST_CHECK_FAILED); goto f_err; } /* Copy the finished so we can use it for renegotiation checks */ if(s->type == SSL_ST_ACCEPT) { OPENSSL_assert(i <= EVP_MAX_MD_SIZE); memcpy(s->s3->previous_client_finished, s->s3->tmp.peer_finish_md, i); s->s3->previous_client_finished_len=i; } else { OPENSSL_assert(i <= EVP_MAX_MD_SIZE); memcpy(s->s3->previous_server_finished, s->s3->tmp.peer_finish_md, i); s->s3->previous_server_finished_len=i; } return(1); f_err: ssl3_send_alert(s,SSL3_AL_FATAL,al); return(0); }
struct mbuf * ieee80211_ccmp_decrypt(struct ieee80211com *ic, struct mbuf *m0, struct ieee80211_key *k) { struct ieee80211_ccmp_ctx *ctx = k->k_priv; struct ieee80211_frame *wh; u_int64_t pn, *prsc; const u_int8_t *ivp, *src; u_int8_t *dst; u_int8_t mic0[IEEE80211_CCMP_MICLEN]; u_int8_t a[16], b[16], s0[16], s[16]; struct mbuf *n0, *m, *n; int hdrlen, left, moff, noff, len; u_int16_t ctr; int i, j; wh = mtod(m0, struct ieee80211_frame *); hdrlen = ieee80211_get_hdrlen(wh); ivp = (u_int8_t *)wh + hdrlen; if (m0->m_pkthdr.len < hdrlen + IEEE80211_CCMP_HDRLEN + IEEE80211_CCMP_MICLEN) { m_freem(m0); return NULL; } /* check that ExtIV bit is set */ if (!(ivp[3] & IEEE80211_WEP_EXTIV)) { m_freem(m0); return NULL; } /* retrieve last seen packet number for this frame type/priority */ if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_DATA) { u_int8_t tid = ieee80211_has_qos(wh) ? ieee80211_get_qos(wh) & IEEE80211_QOS_TID : 0; prsc = &k->k_rsc[tid]; } else /* 11w: management frames have their own counters */ prsc = &k->k_mgmt_rsc; /* extract the 48-bit PN from the CCMP header */ pn = (u_int64_t)ivp[0] | (u_int64_t)ivp[1] << 8 | (u_int64_t)ivp[4] << 16 | (u_int64_t)ivp[5] << 24 | (u_int64_t)ivp[6] << 32 | (u_int64_t)ivp[7] << 40; if (pn <= *prsc) { /* replayed frame, discard */ ic->ic_stats.is_ccmp_replays++; m_freem(m0); return NULL; } MGET(n0, M_DONTWAIT, m0->m_type); if (n0 == NULL) goto nospace; if (m_dup_pkthdr(n0, m0, M_DONTWAIT)) goto nospace; n0->m_pkthdr.len -= IEEE80211_CCMP_HDRLEN + IEEE80211_CCMP_MICLEN; n0->m_len = MHLEN; if (n0->m_pkthdr.len >= MINCLSIZE) { MCLGET(n0, M_DONTWAIT); if (n0->m_flags & M_EXT) n0->m_len = n0->m_ext.ext_size; } if (n0->m_len > n0->m_pkthdr.len) n0->m_len = n0->m_pkthdr.len; /* construct initial B, A and S_0 blocks */ ieee80211_ccmp_phase1(&ctx->rijndael, wh, pn, n0->m_pkthdr.len - hdrlen, b, a, s0); /* copy 802.11 header and clear protected bit */ memcpy(mtod(n0, caddr_t), wh, hdrlen); wh = mtod(n0, struct ieee80211_frame *); wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED; /* construct S_1 */ ctr = 1; a[14] = ctr >> 8; a[15] = ctr & 0xff; rijndael_encrypt(&ctx->rijndael, a, s); /* decrypt frame body and compute MIC */ j = 0; m = m0; n = n0; moff = hdrlen + IEEE80211_CCMP_HDRLEN; noff = hdrlen; left = n0->m_pkthdr.len - noff; while (left > 0) { if (moff == m->m_len) { /* nothing left to copy from m */ m = m->m_next; moff = 0; } if (noff == n->m_len) { /* n is full and there's more data to copy */ MGET(n->m_next, M_DONTWAIT, n->m_type); if (n->m_next == NULL) goto nospace; n = n->m_next; n->m_len = MLEN; if (left >= MINCLSIZE) { MCLGET(n, M_DONTWAIT); if (n->m_flags & M_EXT) n->m_len = n->m_ext.ext_size; } if (n->m_len > left) n->m_len = left; noff = 0; } len = min(m->m_len - moff, n->m_len - noff); src = mtod(m, u_int8_t *) + moff; dst = mtod(n, u_int8_t *) + noff; for (i = 0; i < len; i++) { /* decrypt message */ dst[i] = src[i] ^ s[j]; /* update MIC with clear text */ b[j] ^= dst[i]; if (++j < 16) continue; /* we have a full block, encrypt MIC */ rijndael_encrypt(&ctx->rijndael, b, b); /* construct a new S_ctr block */ ctr++; a[14] = ctr >> 8; a[15] = ctr & 0xff; rijndael_encrypt(&ctx->rijndael, a, s); j = 0; } moff += len; noff += len; left -= len; } if (j != 0) /* partial block, encrypt MIC */ rijndael_encrypt(&ctx->rijndael, b, b); /* finalize MIC, U := T XOR first-M-bytes( S_0 ) */ for (i = 0; i < IEEE80211_CCMP_MICLEN; i++) b[i] ^= s0[i]; /* check that it matches the MIC in received frame */ m_copydata(m, moff, IEEE80211_CCMP_MICLEN, mic0); if (timingsafe_bcmp(mic0, b, IEEE80211_CCMP_MICLEN) != 0) { ic->ic_stats.is_ccmp_dec_errs++; m_freem(m0); m_freem(n0); return NULL; } /* update last seen packet number (MIC is validated) */ *prsc = pn; m_freem(m0); return n0; nospace: ic->ic_stats.is_rx_nombuf++; m_freem(m0); if (n0 != NULL) m_freem(n0); return NULL; }
/* * Verify the given hostname, address and host key using DNS. * Returns 0 if lookup succeeds, -1 otherwise */ int verify_host_key_dns(const char *hostname, struct sockaddr *address, struct sshkey *hostkey, int *flags) { u_int counter; int result; struct rrsetinfo *fingerprints = NULL; u_int8_t hostkey_algorithm; u_int8_t hostkey_digest_type = SSHFP_HASH_RESERVED; u_char *hostkey_digest; size_t hostkey_digest_len; u_int8_t dnskey_algorithm; u_int8_t dnskey_digest_type; u_char *dnskey_digest; size_t dnskey_digest_len; *flags = 0; debug3("verify_host_key_dns"); if (hostkey == NULL) fatal("No key to look up!"); if (is_numeric_hostname(hostname)) { debug("skipped DNS lookup for numerical hostname"); return -1; } result = getrrsetbyname(hostname, DNS_RDATACLASS_IN, DNS_RDATATYPE_SSHFP, 0, &fingerprints); if (result) { verbose("DNS lookup error: %s", dns_result_totext(result)); return -1; } if (fingerprints->rri_flags & RRSET_VALIDATED) { *flags |= DNS_VERIFY_SECURE; debug("found %d secure fingerprints in DNS", fingerprints->rri_nrdatas); } else { debug("found %d insecure fingerprints in DNS", fingerprints->rri_nrdatas); } /* Initialize default host key parameters */ if (!dns_read_key(&hostkey_algorithm, &hostkey_digest_type, &hostkey_digest, &hostkey_digest_len, hostkey)) { error("Error calculating host key fingerprint."); freerrset(fingerprints); return -1; } if (fingerprints->rri_nrdatas) *flags |= DNS_VERIFY_FOUND; for (counter = 0; counter < fingerprints->rri_nrdatas; counter++) { /* * Extract the key from the answer. Ignore any badly * formatted fingerprints. */ if (!dns_read_rdata(&dnskey_algorithm, &dnskey_digest_type, &dnskey_digest, &dnskey_digest_len, fingerprints->rri_rdatas[counter].rdi_data, fingerprints->rri_rdatas[counter].rdi_length)) { verbose("Error parsing fingerprint from DNS."); continue; } if (hostkey_digest_type != dnskey_digest_type) { hostkey_digest_type = dnskey_digest_type; free(hostkey_digest); /* Initialize host key parameters */ if (!dns_read_key(&hostkey_algorithm, &hostkey_digest_type, &hostkey_digest, &hostkey_digest_len, hostkey)) { error("Error calculating key fingerprint."); freerrset(fingerprints); return -1; } } /* Check if the current key is the same as the given key */ if (hostkey_algorithm == dnskey_algorithm && hostkey_digest_type == dnskey_digest_type) { if (hostkey_digest_len == dnskey_digest_len && timingsafe_bcmp(hostkey_digest, dnskey_digest, hostkey_digest_len) == 0) *flags |= DNS_VERIFY_MATCH; } free(dnskey_digest); } free(hostkey_digest); /* from sshkey_fingerprint_raw() */ freerrset(fingerprints); if (*flags & DNS_VERIFY_FOUND) if (*flags & DNS_VERIFY_MATCH) debug("matching host key fingerprint found in DNS"); else debug("mismatching host key fingerprint found in DNS"); else debug("no host key fingerprint found in DNS"); return 0; }
/* SSL 2.0 imlementation for SSL_read/SSL_peek - * This routine will return 0 to len bytes, decrypted etc if required. */ static int ssl2_read_internal(SSL *s, void *buf, int len, int peek) { int n; unsigned char mac[MAX_MAC_SIZE]; unsigned char *p; int i; int mac_size; ssl2_read_again: if (SSL_in_init(s) && !s->in_handshake) { n=s->handshake_func(s); if (n < 0) return(n); if (n == 0) { SSLerr(SSL_F_SSL2_READ_INTERNAL,SSL_R_SSL_HANDSHAKE_FAILURE); return(-1); } } clear_sys_error(); s->rwstate=SSL_NOTHING; if (len <= 0) return(len); if (s->s2->ract_data_length != 0) /* read from buffer */ { if (len > s->s2->ract_data_length) n=s->s2->ract_data_length; else n=len; memcpy(buf,s->s2->ract_data,(unsigned int)n); if (!peek) { s->s2->ract_data_length-=n; s->s2->ract_data+=n; if (s->s2->ract_data_length == 0) s->rstate=SSL_ST_READ_HEADER; } return(n); } /* s->s2->ract_data_length == 0 * * Fill the buffer, then goto ssl2_read_again. */ if (s->rstate == SSL_ST_READ_HEADER) { if (s->first_packet) { n=read_n(s,5,SSL2_MAX_RECORD_LENGTH_2_BYTE_HEADER+2,0); if (n <= 0) return(n); /* error or non-blocking */ s->first_packet=0; p=s->packet; if (!((p[0] & 0x80) && ( (p[2] == SSL2_MT_CLIENT_HELLO) || (p[2] == SSL2_MT_SERVER_HELLO)))) { SSLerr(SSL_F_SSL2_READ_INTERNAL,SSL_R_NON_SSLV2_INITIAL_PACKET); return(-1); } } else { n=read_n(s,2,SSL2_MAX_RECORD_LENGTH_2_BYTE_HEADER+2,0); if (n <= 0) return(n); /* error or non-blocking */ } /* part read stuff */ s->rstate=SSL_ST_READ_BODY; p=s->packet; /* Do header */ /*s->s2->padding=0;*/ s->s2->escape=0; s->s2->rlength=(((unsigned int)p[0])<<8)|((unsigned int)p[1]); if ((p[0] & TWO_BYTE_BIT)) /* Two byte header? */ { s->s2->three_byte_header=0; s->s2->rlength&=TWO_BYTE_MASK; } else { s->s2->three_byte_header=1; s->s2->rlength&=THREE_BYTE_MASK; /* security >s2->escape */ s->s2->escape=((p[0] & SEC_ESC_BIT))?1:0; } } if (s->rstate == SSL_ST_READ_BODY) { n=s->s2->rlength+2+s->s2->three_byte_header; if (n > (int)s->packet_length) { n-=s->packet_length; i=read_n(s,(unsigned int)n,(unsigned int)n,1); if (i <= 0) return(i); /* ERROR */ } p= &(s->packet[2]); s->rstate=SSL_ST_READ_HEADER; if (s->s2->three_byte_header) s->s2->padding= *(p++); else s->s2->padding=0; /* Data portion */ if (s->s2->clear_text) { mac_size = 0; s->s2->mac_data=p; s->s2->ract_data=p; if (s->s2->padding) { SSLerr(SSL_F_SSL2_READ_INTERNAL,SSL_R_ILLEGAL_PADDING); return(-1); } } else { mac_size=EVP_MD_CTX_size(s->read_hash); if (mac_size < 0) return -1; OPENSSL_assert(mac_size <= MAX_MAC_SIZE); s->s2->mac_data=p; s->s2->ract_data= &p[mac_size]; if (s->s2->padding + mac_size > s->s2->rlength) { SSLerr(SSL_F_SSL2_READ_INTERNAL,SSL_R_ILLEGAL_PADDING); return(-1); } } s->s2->ract_data_length=s->s2->rlength; /* added a check for length > max_size in case * encryption was not turned on yet due to an error */ if ((!s->s2->clear_text) && (s->s2->rlength >= (unsigned int)mac_size)) { ssl2_enc(s,0); s->s2->ract_data_length-=mac_size; ssl2_mac(s,mac,0); s->s2->ract_data_length-=s->s2->padding; if ( (timingsafe_bcmp(mac,s->s2->mac_data,mac_size) != 0) || (s->s2->rlength%EVP_CIPHER_CTX_block_size(s->enc_read_ctx) != 0)) { SSLerr(SSL_F_SSL2_READ_INTERNAL,SSL_R_BAD_MAC_DECODE); return(-1); } } INC32(s->s2->read_sequence); /* expect next number */ /* s->s2->ract_data is now available for processing */ /* Possibly the packet that we just read had 0 actual data bytes. * (SSLeay/OpenSSL itself never sends such packets; see ssl2_write.) * In this case, returning 0 would be interpreted by the caller * as indicating EOF, so it's not a good idea. Instead, we just * continue reading; thus ssl2_read_internal may have to process * multiple packets before it can return. * * [Note that using select() for blocking sockets *never* guarantees * that the next SSL_read will not block -- the available * data may contain incomplete packets, and except for SSL 2, * renegotiation can confuse things even more.] */ goto ssl2_read_again; /* This should really be * "return ssl2_read(s,buf,len)", * but that would allow for * denial-of-service attacks if a * C compiler is used that does not * recognize end-recursion. */ } else { SSLerr(SSL_F_SSL2_READ_INTERNAL,SSL_R_BAD_STATE); return(-1); } }