static void natd_hash(const struct hash_desc *hasher, unsigned char *hash, const u_int8_t *icookie, const u_int8_t *rcookie, const ip_address *ip, u_int16_t port /* host order */) { union hash_ctx ctx; if (is_zero_cookie(icookie)) DBG(DBG_NATT, DBG_log("natd_hash: Warning, icookie is zero !!")); if (is_zero_cookie(rcookie)) DBG(DBG_NATT, DBG_log("natd_hash: Warning, rcookie is zero !!")); /* * RFC 3947 * * HASH = HASH(CKY-I | CKY-R | IP | Port) * * All values in network order */ hasher->hash_init(&ctx); hasher->hash_update(&ctx, icookie, COOKIE_SIZE); hasher->hash_update(&ctx, rcookie, COOKIE_SIZE); switch (addrtypeof(ip)) { case AF_INET: hasher->hash_update(&ctx, (const u_char *)&ip->u.v4.sin_addr.s_addr, sizeof(ip->u.v4.sin_addr.s_addr)); break; case AF_INET6: hasher->hash_update(&ctx, (const u_char *)&ip->u.v6.sin6_addr.s6_addr, sizeof(ip->u.v6.sin6_addr.s6_addr)); break; } { u_int16_t netorder_port = htons(port); hasher->hash_update(&ctx, (const u_char *)&netorder_port, sizeof(netorder_port)); } hasher->hash_final(hash, &ctx); DBG(DBG_NATT, { DBG_log("natd_hash: hasher=%p(%d)", hasher, (int)hasher->hash_digest_len); DBG_dump("natd_hash: icookie=", icookie, COOKIE_SIZE); DBG_dump("natd_hash: rcookie=", rcookie, COOKIE_SIZE); switch (addrtypeof(ip)) { case AF_INET: DBG_dump("natd_hash: ip=", &ip->u.v4.sin_addr.s_addr, sizeof(ip->u.v4.sin_addr.s_addr)); break; } DBG_log("natd_hash: port=%d", port); DBG_dump("natd_hash: hash=", hash, hasher->hash_digest_len); });
static void natd_hash(const struct hash_desc *hasher, unsigned char *hash, const u_int8_t *icookie, const u_int8_t *rcookie, const ip_address *ip, u_int16_t port /* host order */) { if (is_zero_cookie(icookie)) DBG(DBG_NATT, DBG_log("natd_hash: Warning, icookie is zero !!")); if (is_zero_cookie(rcookie)) DBG(DBG_NATT, DBG_log("natd_hash: Warning, rcookie is zero !!")); /* * RFC 3947 * * HASH = HASH(CKY-I | CKY-R | IP | Port) * * All values in network order */ struct crypt_hash *ctx = crypt_hash_init(hasher, "NATD", DBG_CRYPT); crypt_hash_digest_bytes(ctx, "ICOOKIE", icookie, COOKIE_SIZE); crypt_hash_digest_bytes(ctx, "RCOOKIE", rcookie, COOKIE_SIZE); switch (addrtypeof(ip)) { case AF_INET: crypt_hash_digest_bytes(ctx, "SIN_ADDR", (const u_char *)&ip->u.v4.sin_addr.s_addr, sizeof(ip->u.v4.sin_addr.s_addr)); break; case AF_INET6: crypt_hash_digest_bytes(ctx, "SIN6_ADDR", (const u_char *)&ip->u.v6.sin6_addr.s6_addr, sizeof(ip->u.v6.sin6_addr.s6_addr)); break; } { u_int16_t netorder_port = htons(port); crypt_hash_digest_bytes(ctx, "PORT", &netorder_port, sizeof(netorder_port)); } crypt_hash_final_bytes(&ctx, hash, hasher->hash_digest_len); DBG(DBG_NATT, { DBG_log("natd_hash: hasher=%p(%d)", hasher, (int)hasher->hash_digest_len); DBG_dump("natd_hash: icookie=", icookie, COOKIE_SIZE); DBG_dump("natd_hash: rcookie=", rcookie, COOKIE_SIZE); switch (addrtypeof(ip)) { case AF_INET: DBG_dump("natd_hash: ip=", &ip->u.v4.sin_addr.s_addr, sizeof(ip->u.v4.sin_addr.s_addr)); break; } DBG_log("natd_hash: port=%d", port); DBG_dump("natd_hash: hash=", hash, hasher->hash_digest_len); });
static void _natd_hash(const struct hash_desc *hasher, unsigned char *hash , u_int8_t *icookie, u_int8_t *rcookie , const ip_address *ip, u_int16_t port) { union hash_ctx ctx; if (is_zero_cookie(icookie)) DBG_log("_natd_hash: Warning, icookie is zero !!"); if (is_zero_cookie(rcookie)) DBG_log("_natd_hash: Warning, rcookie is zero !!"); /** * draft-ietf-ipsec-nat-t-ike-01.txt * * HASH = HASH(CKY-I | CKY-R | IP | Port) * * All values in network order */ hasher->hash_init(&ctx); hasher->hash_update(&ctx, icookie, COOKIE_SIZE); hasher->hash_update(&ctx, rcookie, COOKIE_SIZE); switch (addrtypeof(ip)) { case AF_INET: hasher->hash_update(&ctx, (const u_char *)&ip->u.v4.sin_addr.s_addr, sizeof(ip->u.v4.sin_addr.s_addr)); break; case AF_INET6: hasher->hash_update(&ctx, (const u_char *)&ip->u.v6.sin6_addr.s6_addr, sizeof(ip->u.v6.sin6_addr.s6_addr)); break; } hasher->hash_update(&ctx, (const u_char *)&port, sizeof(u_int16_t)); hasher->hash_final(hash, &ctx); #ifdef NAT_D_DEBUG DBG(DBG_NATT, DBG_log("_natd_hash: hasher=%p(%d)", hasher, (int)hasher->hash_digest_len); DBG_dump("_natd_hash: icookie=", icookie, COOKIE_SIZE); DBG_dump("_natd_hash: rcookie=", rcookie, COOKIE_SIZE); switch (addrtypeof(ip)) { case AF_INET: DBG_dump("_natd_hash: ip=", &ip->u.v4.sin_addr.s_addr, sizeof(ip->u.v4.sin_addr.s_addr)); break; } DBG_log("_natd_hash: port=%d", ntohs(port)); DBG_dump("_natd_hash: hash=", hash, hasher->hash_digest_len); );
/* process an input packet, possibly generating a reply. * * If all goes well, this routine eventually calls a state-specific * transition function. */ void process_packet(struct msg_digest **mdp) { struct msg_digest *md = *mdp; int vmaj, vmin; if (!in_struct(&md->hdr, &isakmp_hdr_desc, &md->packet_pbs, &md->message_pbs)) { /* The packet was very badly mangled. We can't be sure of any * content - not even to look for major version number! * So we'll just drop it. */ libreswan_log("Received packet with mangled IKE header - dropped"); send_notification_from_md(md, PAYLOAD_MALFORMED); return; } if (md->packet_pbs.roof > md->message_pbs.roof) { /* Some (old?) versions of the Cisco VPN client send an additional * 16 bytes of zero bytes - Complain but accept it */ DBG(DBG_CONTROL, { DBG_log( "size (%u) in received packet is larger than the size " "specified in ISAKMP HDR (%u) - ignoring extraneous bytes", (unsigned) pbs_room(&md->packet_pbs), md->hdr.isa_length); DBG_dump("extraneous bytes:", md->message_pbs.roof, md->packet_pbs.roof - md->message_pbs.roof); });
int main(int argc, char *argv[]) { struct state st1; progname = argv[0]; cur_debugging = DBG_CRYPT | DBG_KERNEL | DBG_PARSING; memset(&st1, 0, sizeof(st1)); pluto_shared_secrets_file = "../../baseconfigs/east/etc/ipsec.secrets"; lsw_init_ipsecdir("../../baseconfigs/east/etc/ipsec.d"); lsw_init_rootdir("../../baseconfigs/east"); /* initialize list of moduli */ init_crypto(); load_lswcrypto(); init_seam_kernelalgs(); /* now derive the keys for the CHILD_SA */ { struct ipsec_proto_info *ipi; setchunk(st1.st_skey_d, tc3_results_skey_d, sizeof(tc3_results_skey_d)); ipi = &st1.st_esp; ipi->attrs.transattrs.encrypt = IKEv2_ENCR_AES_CBC; ipi->attrs.transattrs.enckeylen = 128; ipi->attrs.transattrs.integ_hash = alg_info_esp_v2tov1aa( IKEv2_AUTH_HMAC_SHA1_96); ikev2_derive_child_keys(&st1); DBG_dump("our keymat: ", ipi->our_keymat, ipi->keymat_len); DBG_dump("peer keymat: ", ipi->peer_keymat, ipi->keymat_len); } exit(0); }
void calc_nonce(struct pluto_crypto_req *r) { struct pcr_kenonce *kn = &r->pcr_d.kn; pluto_crypto_allocchunk(&kn->thespace, &kn->n, DEFAULT_NONCE_SIZE); get_rnd_bytes(wire_chunk_ptr(kn, &(kn->n)), DEFAULT_NONCE_SIZE); DBG(DBG_CRYPT, DBG_dump("Generated nonce:\n" , wire_chunk_ptr(kn, &(kn->n)) , DEFAULT_NONCE_SIZE)); }
void hmac_update(struct hmac_ctx *ctx, const u_char *data, size_t data_len) { DBG(DBG_CRYPT, DBG_dump("hmac_update data value: ", data, data_len)); if (data_len > 0) { DBG(DBG_CRYPT, DBG_log("hmac_update: inside if")); SECStatus status = PK11_DigestOp(ctx->ctx_nss, data, data_len); DBG(DBG_CRYPT, DBG_log("hmac_update: after digest")); PR_ASSERT(status == SECSuccess); DBG(DBG_CRYPT, DBG_log("hmac_update: after assert")); } }
/* process an input packet, possibly generating a reply. * * If all goes well, this routine eventually calls a state-specific * transition function. */ void process_packet(struct msg_digest **mdp) { struct msg_digest *md = *mdp; struct state *st = NULL; int vmaj, vmin; enum state_kind from_state = STATE_UNDEFINED; /* state we started in */ #define SEND_NOTIFICATION(t) { \ if (st) \ send_notification_from_state(st, from_state, t); \ else \ send_notification_from_md(md, t); } if (!in_struct(&md->hdr, &isakmp_hdr_desc, &md->packet_pbs, &md->message_pbs)) { /* * The packet was very badly mangled. We can't be sure of any * content - not even to look for major version number! * So we'll just silently drop it */ libreswan_log("Received packet with mangled IKE header - dropped"); SEND_NOTIFICATION(PAYLOAD_MALFORMED); return; } if (md->packet_pbs.roof < md->message_pbs.roof) { /* I don't think this can happen if in_struct() did not fail */ libreswan_log( "received packet size (%u) is smaller than from " "size specified in ISAKMP HDR (%u) - packet dropped", (unsigned) pbs_room(&md->packet_pbs), md->hdr.isa_length); /* abort processing corrupt packet */ return; } else if (md->packet_pbs.roof > md->message_pbs.roof) { /* * Some (old?) versions of the Cisco VPN client send an additional * 16 bytes of zero bytes - Complain but accept it */ DBG(DBG_CONTROL, { DBG_log( "size (%u) in received packet is larger than the size " "specified in ISAKMP HDR (%u) - ignoring extraneous bytes", (unsigned) pbs_room(&md->packet_pbs), md->hdr.isa_length); DBG_dump("extraneous bytes:", md->message_pbs.roof, md->packet_pbs.roof - md->message_pbs.roof); });
bool ikev2_calculate_rsa_sha1(struct state *st, enum phase1_role role, unsigned char *idhash, pb_stream *a_pbs) { unsigned char signed_octets[SHA1_DIGEST_SIZE + 16]; size_t signed_len; const struct connection *c = st->st_connection; const struct RSA_private_key *k = get_RSA_private_key(c); unsigned int sz; if (k == NULL) return FALSE; /* failure: no key to use */ sz = k->pub.k; memcpy(signed_octets, der_digestinfo, der_digestinfo_len); ikev2_calculate_sighash(st, role, idhash, st->st_firstpacket_me, signed_octets + der_digestinfo_len); signed_len = der_digestinfo_len + SHA1_DIGEST_SIZE; passert(RSA_MIN_OCTETS <= sz && 4 + signed_len < sz && sz <= RSA_MAX_OCTETS); DBG(DBG_CRYPT, DBG_dump("v2rsa octets", signed_octets, signed_len)); { /* now generate signature blob */ u_char sig_val[RSA_MAX_OCTETS]; int shr; shr = sign_hash(k, signed_octets, signed_len, sig_val, sz); if (shr == 0) return FALSE; passert(shr == (int)sz); if (!out_raw(sig_val, sz, a_pbs, "rsa signature")) return FALSE; } return TRUE; }
bool ikev2_calculate_rsa_sha1(struct state *st , enum phase1_role role , unsigned char *idhash , pb_stream *a_pbs) { unsigned char signed_octets[SHA1_DIGEST_SIZE+16]; size_t signed_len; const struct connection *c = st->st_connection; const struct RSA_private_key *k = get_RSA_private_key(c); unsigned int sz; if (k == NULL) return 0; /* failure: no key to use */ sz = k->pub.k; /* * this is the prefix of the ASN/DER goop that lives inside RSA-SHA1 * signatures. If the signing hash changes, this needs to change * too, but this function is specific to RSA-SHA1. */ memcpy(signed_octets, der_digestinfo, der_digestinfo_len); ikev2_calculate_sighash(st, role, idhash , st->st_firstpacket_me , signed_octets+der_digestinfo_len); signed_len = der_digestinfo_len + SHA1_DIGEST_SIZE; passert(RSA_MIN_OCTETS <= sz && 4 + signed_len < sz && sz <= RSA_MAX_OCTETS); DBG(DBG_CRYPT , DBG_dump("v2rsa octets", signed_octets, signed_len)); { u_char sig_val[RSA_MAX_OCTETS]; /* now generate signature blob */ sign_hash(k, signed_octets, signed_len , sig_val, sz); out_raw(sig_val, sz, a_pbs, "rsa signature"); } return TRUE; }
void calc_ke(struct pluto_crypto_req *r) { MP_INT mp_g; MP_INT secret; chunk_t gi; struct pcr_kenonce *kn = &r->pcr_d.kn; const struct oakley_group_desc *group; group = lookup_group(kn->oakley_group); pluto_crypto_allocchunk(&kn->thespace , &kn->secret , LOCALSECRETSIZE); get_rnd_bytes(wire_chunk_ptr(kn, &(kn->secret)), LOCALSECRETSIZE); n_to_mpz(&secret, wire_chunk_ptr(kn, &(kn->secret)), LOCALSECRETSIZE); mpz_init(&mp_g); oswcrypto.mod_exp(&mp_g, group->generator, &secret, group->modulus); gi = mpz_to_n(&mp_g, group->bytes); pluto_crypto_allocchunk(&kn->thespace, &kn->gi, gi.len); { char *gip = wire_chunk_ptr(kn, &(kn->gi)); memcpy(gip, gi.ptr, gi.len); } DBG(DBG_CRYPT, DBG_dump("Local DH secret:\n" , wire_chunk_ptr(kn, &(kn->secret)) , LOCALSECRETSIZE); DBG_dump_chunk("Public DH value sent:\n", gi)); /* clean up after ourselves */ mpz_clear(&mp_g); mpz_clear(&secret); freeanychunk(gi); }
bool ikev2_calculate_psk_auth(struct state *st, enum original_role role, unsigned char *idhash, pb_stream *a_pbs) { unsigned int hash_len = st->st_oakley.prf_hasher->hash_digest_len; unsigned char signed_octets[hash_len]; if (!ikev2_calculate_psk_sighash(st, role, idhash, st->st_firstpacket_me, signed_octets)) return FALSE; DBG(DBG_PRIVATE, DBG_dump("PSK auth octets", signed_octets, hash_len )); if (!out_raw(signed_octets, hash_len, a_pbs, "PSK auth")) return FALSE; return TRUE; }
void nss_symkey_log(PK11SymKey *key, const char *msg) { if (key != NULL) { DBG(DBG_CRYPT, DBG_log("computed key %s with length =%d", msg, PK11_GetKeyLength(key))); } else { DBG_log("NULL key %s", msg); } if (!PK11_IsFIPS()) { if (key != NULL) { SECStatus status = PK11_ExtractKeyValue(key); PR_ASSERT(status == SECSuccess); SECItem *keydata = PK11_GetKeyData(key); DBG(DBG_CRYPT, DBG_dump("value: ", keydata->data, keydata->len)); /* SECITEM_FreeItem(keydata, PR_TRUE); */ } } }
/** * nat_traversal_natoa_lookup() * * Look for NAT-OA in message */ void nat_traversal_natoa_lookup(struct msg_digest *md) { struct payload_digest *p; struct state *st = md->st; int i; ip_address ip; if (!st || !md->iface) { loglog(RC_LOG_SERIOUS, "NAT-Traversal: assert failed %s:%d", __FILE__, __LINE__); return; } /** Count NAT-OA **/ for (p = md->chain[ISAKMP_NEXT_NATOA_R], i=0; p != NULL; p = p->next, i++); #if 0 DBG_log("NAT-Traversal: received %d NAT-OA.", i); #endif if (i==0) { return; } else if (!(st->nat_traversal & LELEM(NAT_TRAVERSAL_NAT_BHND_PEER))) { loglog(RC_LOG_SERIOUS, "NAT-Traversal: received %d NAT-OA. " "ignored because peer is not NATed", i); return; } else if (i>1) { loglog(RC_LOG_SERIOUS, "NAT-Traversal: received %d NAT-OA. " "using first, ignoring others", i); } /** Take first **/ p = md->chain[ISAKMP_NEXT_NATOA_R]; DBG(DBG_PARSING, DBG_dump("NAT-OA:", p->pbs.start, pbs_room(&p->pbs)); );
stf_status ikev2_verify_psk_auth(struct state *st, enum original_role role, unsigned char *idhash, pb_stream *sig_pbs) { unsigned int hash_len = st->st_oakley.prf_hasher->hash_digest_len; unsigned char calc_hash[hash_len]; size_t sig_len = pbs_left(sig_pbs); enum original_role invertrole; invertrole = (role == ORIGINAL_INITIATOR ? ORIGINAL_RESPONDER : ORIGINAL_INITIATOR); if (sig_len != hash_len) { libreswan_log("negotiated prf: %s ", st->st_oakley.prf_hasher->common.name); libreswan_log( "I2 hash length:%lu does not match with PRF hash len %lu", (long unsigned) sig_len, (long unsigned) hash_len); return STF_FAIL; } if (!ikev2_calculate_psk_sighash(st, invertrole, idhash, st->st_firstpacket_him, calc_hash)) return STF_FAIL; DBG(DBG_PRIVATE, DBG_dump("Received PSK auth octets", sig_pbs->cur, sig_len); DBG_dump("Calculated PSK auth octets", calc_hash, hash_len)); if (memeq(sig_pbs->cur, calc_hash, hash_len) ) { return STF_OK; } else { libreswan_log("AUTH mismatch: Received AUTH != computed AUTH"); return STF_FAIL; } }
void init_vendorid(void) { struct vid_struct *vid; MD5_CTX ctx; int i; for (vid = _vid_tab; vid->id; vid++) { if (vid->flags & VID_STRING) { /** VendorID is a string **/ vid->vid = strdup(vid->data); vid->vid_len = strlen(vid->data); } else if (vid->flags & VID_MD5HASH) { /** VendorID is a string to hash with MD5 **/ char *vidm = malloc(MD5_DIGEST_SIZE); vid->vid = vidm; if (vidm) { MD5Init(&ctx); MD5Update(&ctx, (unsigned char *)vid->data, strlen(vid->data)); MD5Final(vidm, &ctx); vid->vid_len = MD5_DIGEST_SIZE; } } else if (vid->flags & VID_FSWAN_HASH) { /** FreeS/WAN 2.00+ specific hash **/ #define FSWAN_VID_SIZE 12 unsigned char hash[MD5_DIGEST_SIZE]; char *vidm = malloc(FSWAN_VID_SIZE); vid->vid = vidm; if (vidm) { MD5Init(&ctx); MD5Update(&ctx, (unsigned char *)vid->data, strlen(vid->data)); MD5Final(hash, &ctx); vidm[0] = 'O'; vidm[1] = 'E'; #if FSWAN_VID_SIZE - 2 <= MD5_DIGEST_SIZE memcpy(vidm + 2, hash, FSWAN_VID_SIZE - 2); #else memcpy(vidm + 2, hash, MD5_DIGEST_SIZE); memset(vidm + 2 + MD5_DIGEST_SIZE, '\0', FSWAN_VID_SIZE - 2 - MD5_DIGEST_SIZE); #endif for (i = 2; i < FSWAN_VID_SIZE; i++) { vidm[i] &= 0x7f; vidm[i] |= 0x40; } vid->vid_len = FSWAN_VID_SIZE; } } if (vid->descr == NULL) { /** Find something to display **/ vid->descr = vid->data; } #if 0 DBG_log("vendorid_init: %d [%s]", vid->id, vid->descr ? vid->descr : "" ); if (vid->vid) DBG_dump("VID:", vid->vid, vid->vid_len); #endif } _vid_struct_init = 1; }
err_t try_RSA_signature_v2(const u_char hash_val[MAX_DIGEST_LEN] , size_t hash_len , const pb_stream *sig_pbs, struct pubkey *kr , struct state *st) { const u_char *sig_val = sig_pbs->cur; size_t sig_len = pbs_left(sig_pbs); u_char s[RSA_MAX_OCTETS]; /* for decrypted sig_val */ u_char *sig; unsigned int padlen; const struct RSA_public_key *k = &kr->u.rsa; if (k == NULL) return "1""no key available"; /* failure: no key to use */ /* decrypt the signature -- reversing RSA_sign_hash */ if (sig_len != k->k) { DBG_log("sig_len: %u != k->k: %u" , (unsigned int)sig_len, (unsigned int)k->k); return "1""SIG length does not match public key length"; } /* actual exponentiation; see PKCS#1 v2.0 5.1 */ { chunk_t temp_s; MP_INT c; n_to_mpz(&c, sig_val, sig_len); oswcrypto.mod_exp(&c, &c, &k->e, &k->n); temp_s = mpz_to_n(&c, sig_len); /* back to octets */ memcpy(s, temp_s.ptr, sig_len); pfree(temp_s.ptr); mpz_clear(&c); } /* check signature contents */ /* verify padding */ padlen = sig_len - 3 - (hash_len+der_digestinfo_len); /* now check padding */ sig = s; DBG(DBG_CRYPT, DBG_dump("v2rsa decrypted SIG1:", sig, sig_len)); if(sig[0] != 0x00 || sig[1] != 0x01 || sig[padlen+2] != 0x00) { return "2""SIG padding does not check out"; } /* skip padding */ sig += padlen+3; /* 2 verify that the has was done with SHA1 */ if(memcmp(der_digestinfo, sig, der_digestinfo_len)!=0) { return "SIG not performed with SHA1"; } sig += der_digestinfo_len; DBG(DBG_CRYPT, DBG_dump("v2rsa decrypted SIG:", hash_val, hash_len); DBG_dump("v2rsa computed hash:", sig, hash_len); );
err_t RSA_signature_verify_nss(const struct RSA_public_key *k , const u_char *hash_val, size_t hash_len ,const u_char *sig_val, size_t sig_len) { SECKEYPublicKey *publicKey; PRArenaPool *arena; SECStatus retVal = SECSuccess; SECItem nss_n, nss_e; SECItem signature, data; chunk_t n,e; /*Converting n and e to form public key in SECKEYPublicKey data structure*/ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if (arena == NULL) { PORT_SetError (SEC_ERROR_NO_MEMORY); return "10" "NSS error: Not enough memory to create arena"; } publicKey = (SECKEYPublicKey *) PORT_ArenaZAlloc (arena, sizeof (SECKEYPublicKey)); if (!publicKey) { PORT_FreeArena (arena, PR_FALSE); PORT_SetError (SEC_ERROR_NO_MEMORY); return "11" "NSS error: Not enough memory to create publicKey"; } publicKey->arena = arena; publicKey->keyType = rsaKey; publicKey->pkcs11Slot = NULL; publicKey->pkcs11ID = CK_INVALID_HANDLE; /* Converting n(modulus) and e(exponent) from mpz_t form to chunk_t */ n = mpz_to_n_autosize(&k->n); e = mpz_to_n_autosize(&k->e); /*Converting n and e to nss_n and nss_e*/ nss_n.data = n.ptr; nss_n.len = (unsigned int)n.len; nss_n.type = siBuffer; nss_e.data = e.ptr; nss_e.len = (unsigned int)e.len; nss_e.type = siBuffer; retVal = SECITEM_CopyItem(arena, &publicKey->u.rsa.modulus, &nss_n); if (retVal == SECSuccess) { retVal = SECITEM_CopyItem (arena, &publicKey->u.rsa.publicExponent, &nss_e); } if(retVal != SECSuccess) { pfree(n.ptr); pfree(e.ptr); SECKEY_DestroyPublicKey (publicKey); return "12" "NSS error: Not able to copy modulus or exponent or both while forming SECKEYPublicKey structure"; } signature.type = siBuffer; signature.data = DISCARD_CONST(unsigned char *, sig_val); signature.len = (unsigned int)sig_len; data.len = (unsigned int)sig_len; data.data = alloc_bytes(data.len, "NSS decrypted signature"); data.type = siBuffer; if(PK11_VerifyRecover(publicKey, &signature, &data, osw_return_nss_password_file_info()) == SECSuccess ) { DBG(DBG_CRYPT,DBG_dump("NSS RSA verify: decrypted sig: ", data.data, data.len)); } else { DBG(DBG_CRYPT,DBG_log("NSS RSA verify: decrypting signature is failed")); return "13" "NSS error: Not able to decrypt"; } if(memcmp(data.data+data.len-hash_len, hash_val, hash_len)!=0) { pfree(data.data); loglog(RC_LOG_SERIOUS, "RSA Signature NOT verified"); return "14" "NSS error: Not able to verify"; } DBG(DBG_CRYPT,DBG_dump("NSS RSA verify: hash value: ", hash_val, hash_len)); pfree(data.data); pfree(n.ptr); pfree(e.ptr); SECKEY_DestroyPublicKey (publicKey); DBG(DBG_CRYPT, DBG_log("RSA Signature verified")); return NULL; }
void recv_pcap_packet_gen(u_char *user, const struct pcap_pkthdr *h, const u_char *bytes) { struct msg_digest *md; u_int32_t *dlt; struct iphdr *ip; struct udphdr *udp; u_char *ike; const struct iface_port *ifp = &if1; int packet_len; err_t from_ugh; union { struct sockaddr sa; struct sockaddr_in sa_in4; struct sockaddr_in6 sa_in6; } from; md = alloc_md(); dlt = (u_int32_t *)bytes; if (*dlt != PF_INET) return; ip = (struct iphdr *)(dlt + 1); udp = (struct udphdr *)(dlt + ip->ihl + 1); ike = (u_char *)(udp + 1); from.sa_in4.sin_addr.s_addr = ip->saddr; from.sa_in4.sin_port = udp->source; md->iface = ifp; packet_len = h->len - (ike - bytes); happy(anyaddr(addrtypeof(&ifp->ip_addr), &md->sender)); from_ugh = initaddr((void *) &from.sa_in4.sin_addr, sizeof(from.sa_in4.sin_addr), AF_INET, &md->sender); setportof(from.sa_in4.sin_port, &md->sender); md->sender_port = ntohs(from.sa_in4.sin_port); cur_from = &md->sender; cur_from_port = md->sender_port; /* Clone actual message contents * and set up md->packet_pbs to describe it. */ init_pbs(&md->packet_pbs, clone_bytes(ike, packet_len, "message buffer in comm_handle()"), packet_len, "packet"); DBG_log("*received %d bytes from %s:%u on %s (port=%d)", (int) pbs_room(&md->packet_pbs), ip_str(&md->sender), (unsigned) md->sender_port, ifp->ip_dev->id_rname, ifp->port); DBG_dump("", md->packet_pbs.start, pbs_room(&md->packet_pbs)); process_packet(&md); if (md != NULL) release_md(md); cur_state = NULL; reset_cur_connection(); cur_from = NULL; }
void calc_ke(struct pluto_crypto_req *r) { chunk_t prime; chunk_t base; SECKEYDHParams dhp; PK11SlotInfo *slot = NULL; SECKEYPrivateKey *privk; SECKEYPublicKey *pubk; struct pcr_kenonce *kn = &r->pcr_d.kn; const struct oakley_group_desc *group; group = lookup_group(kn->oakley_group); base = mpz_to_n2(group->generator); prime = mpz_to_n2(group->modulus); DBG(DBG_CRYPT,DBG_dump_chunk("NSS: Value of Prime:\n", prime)); DBG(DBG_CRYPT,DBG_dump_chunk("NSS: Value of base:\n", base)); dhp.prime.data=prime.ptr; dhp.prime.len=prime.len; dhp.base.data=base.ptr; dhp.base.len=base.len; slot = PK11_GetBestSlot(CKM_DH_PKCS_KEY_PAIR_GEN,osw_return_nss_password_file_info()); if(!slot) { loglog(RC_LOG_SERIOUS, "NSS: slot for DH key gen is NULL"); } PR_ASSERT(slot!=NULL); while(1) { privk = PK11_GenerateKeyPair(slot, CKM_DH_PKCS_KEY_PAIR_GEN, &dhp, &pubk, PR_FALSE, PR_TRUE, osw_return_nss_password_file_info()); if(!privk) { loglog(RC_LOG_SERIOUS, "NSS: DH private key creation failed (err %d)", PR_GetError()); } PR_ASSERT(privk!=NULL); if( group-> bytes == pubk->u.dh.publicValue.len ) { DBG(DBG_CRYPT, DBG_log("NSS: generated dh priv and pub keys: %d\n", pubk->u.dh.publicValue.len)); break; } else { DBG(DBG_CRYPT, DBG_log("NSS: generating dh priv and pub keys")); if (privk) SECKEY_DestroyPrivateKey(privk); if (pubk) SECKEY_DestroyPublicKey(pubk); } } pluto_crypto_allocchunk(&kn->thespace, &kn->secret, sizeof(SECKEYPrivateKey*)); { char *gip = wire_chunk_ptr(kn, &(kn->secret)); memcpy(gip, &privk, sizeof(SECKEYPrivateKey *)); } pluto_crypto_allocchunk(&kn->thespace, &kn->gi, pubk->u.dh.publicValue.len); { char *gip = wire_chunk_ptr(kn, &(kn->gi)); memcpy(gip, pubk->u.dh.publicValue.data, pubk->u.dh.publicValue.len); } pluto_crypto_allocchunk(&kn->thespace, &kn->pubk, sizeof(SECKEYPublicKey*)); { char *gip = wire_chunk_ptr(kn, &(kn->pubk)); memcpy(gip, &pubk, sizeof(SECKEYPublicKey*)); } DBG(DBG_CRYPT, DBG_dump("NSS: Local DH secret:\n" , wire_chunk_ptr(kn, &(kn->secret)) , sizeof(SECKEYPrivateKey*)); DBG_dump("NSS: Public DH value sent(computed in NSS):\n", wire_chunk_ptr(kn, &(kn->gi)),pubk->u.dh.publicValue.len)); DBG(DBG_CRYPT, DBG_dump("NSS: Local DH public value (pointer):\n" , wire_chunk_ptr(kn, &(kn->pubk)) , sizeof(SECKEYPublicKey*))); /* clean up after ourselves */ if (slot) { PK11_FreeSlot(slot); } /* if (privk){SECKEY_DestroyPrivateKey(privk);} */ /* if (pubk){SECKEY_DestroyPublicKey(pubk);} */ freeanychunk(prime); freeanychunk(base); }
/* * Setup VendorID structs, and populate them * FIXME: This functions leaks a little bit, but these are one time leaks: * leak: 3 * vid->data, item size: 6 * leak: self-vendor ID, item size: 37 * leak: init_pluto_vendorid, item size: 13 * leak: 2 * vid->data, item size: 13 */ void init_vendorid(void) { struct vid_struct *vid; for (vid = vid_tab; vid->id; vid++) { if (vid->flags & VID_SELF) { char *d; vid->vid = clone_str( ipsec_version_vendorid(), "init_pluto_vendorid"); /* cut terminating NULL which won't go over the wire */ vid->vid_len = strlen(vid->vid); d = alloc_bytes(strlen(vid->descr) + 256 + strlen(ipsec_version_vendorid()), "self-vendor ID"); sprintf(d, "%s %s", vid->descr, ipsec_version_code()); vid->descr = (const char *)d; } else if (vid->flags & VID_STRING) { /** VendorID is a string **/ vid->vid = clone_str(vid->data, "vid->data"); vid->vid_len = strlen(vid->data); } else if (vid->flags & VID_MD5HASH) { /** VendorID is a string to hash with MD5 **/ unsigned char *vidm = alloc_bytes(MD5_DIGEST_SIZE, "VendorID MD5"); vid->vid = (char *)vidm; if (vidm) { unsigned const char *d = (unsigned const char *)vid->data; MD5_CTX ctx; osMD5Init(&ctx); osMD5Update(&ctx, d, strlen(vid->data)); osMD5Final(vidm, &ctx); vid->vid_len = MD5_DIGEST_SIZE; } } else if (vid->flags & VID_FSWAN_HASH) { /** FreeS/WAN 2.00+ specific hash **/ #define FSWAN_VID_SIZE 12 unsigned char hash[MD5_DIGEST_SIZE]; char *vidm = alloc_bytes(FSWAN_VID_SIZE, "fswan VID"); vid->vid = vidm; if (vidm) { MD5_CTX ctx; int i; osMD5Init(&ctx); osMD5Update(&ctx, (const unsigned char *)vid->data, strlen( vid->data)); osMD5Final(hash, &ctx); vidm[0] = 'O'; vidm[1] = 'E'; #if FSWAN_VID_SIZE <= 2 + MD5_DIGEST_SIZE memcpy(vidm + 2, hash, FSWAN_VID_SIZE - 2); /* truncate hash */ #else memcpy(vidm + 2, hash, MD5_DIGEST_SIZE); memset(vidm + 2 + MD5_DIGEST_SIZE, '\0', FSWAN_VID_SIZE - (2 + MD5_DIGEST_SIZE)); /* pad hash */ #endif for (i = 2; i < FSWAN_VID_SIZE; i++) { vidm[i] &= 0x7f; vidm[i] |= 0x40; } vid->vid_len = FSWAN_VID_SIZE; } #undef FSWAN_VID_SIZE } if (vid->descr == NULL) { /** Find something to display **/ vid->descr = vid->data; } #if 1 DBG_log("init_vendorid: %d [%s]", vid->id, vid->descr ? vid->descr : "" ); if (vid->vid) DBG_dump("VID:", vid->vid, vid->vid_len); #endif } vid_struct_init = 1; }
void nat_traversal_natd_lookup(struct msg_digest *md) { char hash[MAX_DIGEST_LEN]; struct payload_digest *p; struct state *st = md->st; int i; if (!st || !md->iface || !st->st_oakley.hasher) { loglog(RC_LOG_SERIOUS, "NAT-Traversal: assert failed %s:%d", __FILE__, __LINE__); return; } /** Count NAT-D **/ for (p = md->chain[ISAKMP_NEXT_NATD_R], i=0; p != NULL; p = p->next, i++); /** * We need at least 2 NAT-D (1 for us, many for peer) */ if (i < 2) { loglog(RC_LOG_SERIOUS, "NAT-Traversal: Only %d NAT-D - Aborting NAT-Traversal negotiation", i); st->nat_traversal = 0; return; } #ifdef NAT_D_DEBUG else loglog(RC_LOG_SERIOUS, "NAT-Traversal: %d NAT-D - Continuing NAT-Traversal negotiation", i); #endif /** * First one with my IP & port */ p = md->chain[ISAKMP_NEXT_NATD_R]; _natd_hash(st->st_oakley.hasher, hash, st->st_icookie, st->st_rcookie, &(md->iface->addr), ntohs(st->st_connection->this.host_port)); if (!( (pbs_left(&p->pbs) == st->st_oakley.hasher->hash_digest_len) && (memcmp(p->pbs.cur, hash, st->st_oakley.hasher->hash_digest_len)==0) )) { #ifdef NAT_D_DEBUG DBG_log("NAT_TRAVERSAL_NAT_BHND_ME"); DBG_dump("expected NAT-D:", hash, st->st_oakley.hasher->hash_digest_len); DBG_dump("received NAT-D:", p->pbs.cur, pbs_left(&p->pbs)); #endif st->nat_traversal |= LELEM(NAT_TRAVERSAL_NAT_BHND_ME); } /** * The others with sender IP & port */ _natd_hash(st->st_oakley.hasher, hash, st->st_icookie, st->st_rcookie, &(md->sender), ntohs(md->sender_port)); for (p = p->next, i=0 ; p != NULL; p = p->next) { if ( (pbs_left(&p->pbs) == st->st_oakley.hasher->hash_digest_len) && (memcmp(p->pbs.cur, hash, st->st_oakley.hasher->hash_digest_len)==0) ) { i++; } } if (!i) { #ifdef NAT_D_DEBUG DBG_log("NAT_TRAVERSAL_NAT_BHND_PEER"); DBG_dump("expected NAT-D:", hash, st->st_oakley.hasher->hash_digest_len); p = md->chain[ISAKMP_NEXT_NATD_R]; for (p = p->next, i=0 ; p != NULL; p = p->next) { DBG_dump("received NAT-D:", p->pbs.cur, pbs_left(&p->pbs)); } #endif st->nat_traversal |= LELEM(NAT_TRAVERSAL_NAT_BHND_PEER); } #ifdef FORCE_NAT_TRAVERSAL st->nat_traversal |= LELEM(NAT_TRAVERSAL_NAT_BHND_PEER); st->nat_traversal |= LELEM(NAT_TRAVERSAL_NAT_BHND_ME); #endif }
/* * Setup VendorID structs, and populate them * FIXME: This functions leaks a little bit, but these are one time leaks: * leak: 3 * vid->data, item size: 6 * leak: self-vendor ID, item size: 37 * leak: 2 * vid->data, item size: 13 */ void init_vendorid(void) { struct vid_struct *vid; for (vid = vid_tab; vid->id; vid++) { if (vid->flags & VID_SELF) { vid->vid_len = strlen(vid->vid); } else if (vid->flags & VID_STRING) { /** VendorID is a string **/ vid->vid = clone_str(vid->data, "vid->data (ignore)"); /* clang 3.4 thinks that vid->data might be NULL but it won't be */ vid->vid_len = strlen(vid->data); } else if (vid->flags & VID_MD5HASH) { /** VendorID is a string to hash with MD5 **/ unsigned char *vidm = alloc_bytes(MD5_DIGEST_SIZE, "VendorID MD5 (ignore)"); const unsigned char *d = (const unsigned char *)vid->data; lsMD5_CTX ctx; vid->vid = (char *)vidm; lsMD5Init(&ctx); lsMD5Update(&ctx, d, strlen(vid->data)); lsMD5Final(vidm, &ctx); vid->vid_len = MD5_DIGEST_SIZE; } else if (vid->flags & VID_FSWAN_HASH) { /** FreeS/WAN 2.00+ specific hash **/ #define FSWAN_VID_SIZE 12 unsigned char hash[MD5_DIGEST_SIZE]; char *vidm = alloc_bytes(FSWAN_VID_SIZE, "fswan VID (ignore)"); lsMD5_CTX ctx; int i; vid->vid = vidm; lsMD5Init(&ctx); lsMD5Update(&ctx, (const unsigned char *)vid->data, strlen(vid->data)); lsMD5Final(hash, &ctx); vidm[0] = 'O'; vidm[1] = 'E'; #if FSWAN_VID_SIZE <= 2 + MD5_DIGEST_SIZE memcpy(vidm + 2, hash, FSWAN_VID_SIZE - 2); /* truncate hash */ #else memcpy(vidm + 2, hash, MD5_DIGEST_SIZE); memset(vidm + 2 + MD5_DIGEST_SIZE, '\0', FSWAN_VID_SIZE - (2 + MD5_DIGEST_SIZE)); /* pad hash */ #endif for (i = 2; i < FSWAN_VID_SIZE; i++) { vidm[i] &= 0x7f; vidm[i] |= 0x40; } vid->vid_len = FSWAN_VID_SIZE; #undef FSWAN_VID_SIZE } if (vid->descr == NULL) { /** Find something to display **/ vid->descr = vid->data; } #if 0 DBG_log("init_vendorid: %d [%s]", vid->id, vid->descr == NULL ? vid->descr : ""); if (vid->vid) DBG_dump("VID:", vid->vid, vid->vid_len); #endif } }
/* print a host struct * * This code assumes that the network and host structure * members have the same alignment and size! This requires * that all padding be explicit. */ void DBG_print_struct(const char *label, const void *struct_ptr , struct_desc *sd, bool len_meaningful) { bool immediate = FALSE; const u_int8_t *inp = struct_ptr; field_desc *fp; DBG_log("%s%s:", label, sd->name); for (fp = sd->fields; fp->field_type != ft_end; fp++) { int i = fp->size; u_int32_t n = 0; switch (fp->field_type) { case ft_mbz: /* must be zero */ inp += i; break; case ft_nat: /* natural number (may be 0) */ case ft_len: /* length of this struct and any following crud */ case ft_lv: /* length/value field of attribute */ case ft_enum: /* value from an enumeration */ case ft_loose_enum: /* value from an enumeration with only some names known */ case ft_af_enum: /* Attribute Format + value from an enumeration */ case ft_set: /* bits representing set */ switch (i) { case 8/BITS_PER_BYTE: n = *(const u_int8_t *)inp; break; case 16/BITS_PER_BYTE: n = *(const u_int16_t *)inp; break; case 32/BITS_PER_BYTE: n = *(const u_int32_t *)inp; break; default: impossible(); } switch (fp->field_type) { case ft_len: /* length of this struct and any following crud */ case ft_lv: /* length/value field of attribute */ if (!immediate && !len_meaningful) break; /* FALL THROUGH */ case ft_nat: /* natural number (may be 0) */ DBG_log(" %s: %lu", fp->name, (unsigned long)n); break; case ft_af_enum: /* Attribute Format + value from an enumeration */ if ((n & ISAKMP_ATTR_AF_MASK) == ISAKMP_ATTR_AF_TV) immediate = TRUE; /* FALL THROUGH */ case ft_enum: /* value from an enumeration */ case ft_loose_enum: /* value from an enumeration with only some names known */ DBG_log(" %s: %s", fp->name, enum_show(fp->desc, n)); break; case ft_set: /* bits representing set */ DBG_log(" %s: %s", fp->name, bitnamesof(fp->desc, n)); break; default: impossible(); break; } inp += i; break; case ft_raw: /* bytes to be left in network-order */ { char m[50]; /* arbitrary limit on name width in log */ snprintf(m, sizeof(m), " %s:", fp->name); DBG_dump(m, inp, i); inp += i; } break; default: impossible(); break; } } }
/* MUST BE THREAD-SAFE */ void calc_ke(struct pluto_crypto_req *r) { SECKEYDHParams dhp; PK11SlotInfo *slot = NULL; SECKEYPrivateKey *privk; SECKEYPublicKey *pubk; struct pcr_kenonce *kn = &r->pcr_d.kn; const struct oakley_group_desc *group = lookup_group(kn->oakley_group); chunk_t base = mpz_to_n_autosize(group->generator); chunk_t prime = mpz_to_n_autosize(group->modulus); DBG(DBG_CRYPT, DBG_dump_chunk("NSS: Value of Prime:", prime)); DBG(DBG_CRYPT, DBG_dump_chunk("NSS: Value of base:", base)); dhp.prime.data = prime.ptr; dhp.prime.len = prime.len; dhp.base.data = base.ptr; dhp.base.len = base.len; slot = PK11_GetBestSlot(CKM_DH_PKCS_KEY_PAIR_GEN, lsw_return_nss_password_file_info()); if (slot == NULL) loglog(RC_LOG_SERIOUS, "NSS: slot for DH key gen is NULL"); passert(slot != NULL); for (;;) { pubk = NULL; /* ??? is this needed? Output-only from next call? */ privk = PK11_GenerateKeyPair(slot, CKM_DH_PKCS_KEY_PAIR_GEN, &dhp, &pubk, PR_FALSE, PR_TRUE, lsw_return_nss_password_file_info()); if (privk == NULL) { loglog(RC_LOG_SERIOUS, "NSS: DH private key creation failed (err %d)", PR_GetError()); } passert(privk != NULL && pubk != NULL); if (group->bytes == pubk->u.dh.publicValue.len) { DBG(DBG_CRYPT, DBG_log("NSS: generated dh priv and pub keys: %d", pubk->u.dh.publicValue.len)); break; } else { DBG(DBG_CRYPT, DBG_log("NSS: generating dh priv and pub keys again")); SECKEY_DestroyPrivateKey(privk); SECKEY_DestroyPublicKey(pubk); } } kn->secret = privk; kn->pubk = pubk; ALLOC_WIRE_CHUNK(*kn, gi, pubk->u.dh.publicValue.len); { unsigned char *gip = WIRE_CHUNK_PTR(*kn, gi); memcpy(gip, pubk->u.dh.publicValue.data, pubk->u.dh.publicValue.len); } DBG(DBG_CRYPT, { DBG_log("NSS: Local DH secret (pointer): %p", kn->secret); DBG_dump("NSS: Public DH value sent(computed in NSS):", WIRE_CHUNK_PTR(*kn, gi), pubk->u.dh.publicValue.len); });
/* Finish (building, sending, accepting response for) PF_KEY message. * If response isn't NULL, the response from the kernel will be * placed there (and its errno field will not be examined). * Returns TRUE iff all appears well. */ static bool finish_pfkey_msg(struct sadb_ext *extensions[SADB_EXT_MAX + 1] , const char *description , const char *text_said , pfkey_buf *response) { struct sadb_msg *pfkey_msg; bool success = TRUE; int error; error = pfkey_msg_build(&pfkey_msg, extensions, EXT_BITS_IN); if (error != 0) { loglog(RC_LOG_SERIOUS, "pfkey_msg_build of %s %s failed, code %d" , description, text_said, error); success = FALSE; } else { size_t len = pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN; DBG(DBG_KLIPS, DBG_log("finish_pfkey_msg: %s message %u for %s %s" , sparse_val_show(pfkey_type_names, pfkey_msg->sadb_msg_type) , pfkey_msg->sadb_msg_seq , description, text_said); DBG_dump(NULL, (void *) pfkey_msg, len)); if (!no_klips) { ssize_t r = write(pfkeyfd, pfkey_msg, len); if (r != (ssize_t)len) { if (r < 0) { log_errno((e , "pfkey write() of %s message %u" " for %s %s failed" , sparse_val_show(pfkey_type_names , pfkey_msg->sadb_msg_type) , pfkey_msg->sadb_msg_seq , description, text_said)); } else { loglog(RC_LOG_SERIOUS , "ERROR: pfkey write() of %s message %u" " for %s %s truncated: %ld instead of %ld" , sparse_val_show(pfkey_type_names , pfkey_msg->sadb_msg_type) , pfkey_msg->sadb_msg_seq , description, text_said , (long)r, (long)len); } success = FALSE; /* if we were compiled with debugging, but we haven't already * dumped the KLIPS command, do so. */ #ifdef DEBUG if ((cur_debugging & DBG_KLIPS) == 0) DBG_dump(NULL, (void *) pfkey_msg, len); #endif } else { /* Check response from KLIPS. * It ought to be an echo, perhaps with additional info. * If the caller wants it, response will point to space. */ pfkey_buf b; pfkey_buf *bp = response != NULL? response : &b; if (!pfkey_get_response(bp, ((struct sadb_msg *) extensions[0])->sadb_msg_seq)) { loglog(RC_LOG_SERIOUS , "ERROR: no response to our PF_KEY %s message for %s %s" , sparse_val_show(pfkey_type_names, pfkey_msg->sadb_msg_type) , description, text_said); success = FALSE; } else if (pfkey_msg->sadb_msg_type != bp->msg.sadb_msg_type) { loglog(RC_LOG_SERIOUS , "FreeS/WAN ERROR: response to our PF_KEY %s message for %s %s was of wrong type (%s)" , sparse_name(pfkey_type_names, pfkey_msg->sadb_msg_type) , description, text_said , sparse_val_show(pfkey_type_names, bp->msg.sadb_msg_type)); success = FALSE; } else if (response == NULL && bp->msg.sadb_msg_errno != 0) { /* KLIPS is signalling a problem */ loglog(RC_LOG_SERIOUS , "ERROR: PF_KEY %s response for %s %s included errno %u: %s" , sparse_val_show(pfkey_type_names, pfkey_msg->sadb_msg_type) , description, text_said , (unsigned) bp->msg.sadb_msg_errno , strerror(bp->msg.sadb_msg_errno)); success = FALSE; } } } } /* all paths must exit this way to free resources */ pfkey_extensions_free(extensions); pfkey_msg_free(&pfkey_msg); return success; }