/* decode of RSA pubkey chunk * - format specified in RFC 2537 RSA/MD5 Keys and SIGs in the DNS * - exponent length in bytes (1 or 3 octets) * + 1 byte if in [1, 255] * + otherwise 0x00 followed by 2 bytes of length * - exponent * - modulus */ err_t unpack_RSA_public_key(struct RSA_public_key *rsa, const chunk_t *pubkey) { chunk_t exponent; chunk_t mod; rsa->keyid[0] = '\0'; /* in case of keybolbtoid failure */ if (pubkey->len < 3) return "RSA public key blob way to short"; /* not even room for length! */ rsa->key_rfc3110 = chunk_clone(*pubkey, "rfc3110 format of public key"); if (pubkey->ptr[0] != 0x00) { setchunk(exponent, pubkey->ptr + 1, pubkey->ptr[0]); } else { setchunk(exponent, pubkey->ptr + 3 , (pubkey->ptr[1] << BITS_PER_BYTE) + pubkey->ptr[2]); } if (pubkey->len - (exponent.ptr - pubkey->ptr) < exponent.len + RSA_MIN_OCTETS_RFC) return "RSA public key blob too short"; mod.ptr = exponent.ptr + exponent.len; mod.len = &pubkey->ptr[pubkey->len] - mod.ptr; if (mod.len < RSA_MIN_OCTETS) return RSA_MIN_OCTETS_UGH; if (mod.len > RSA_MAX_OCTETS) return RSA_MAX_OCTETS_UGH; if (mod.len > pubkey->ptr + pubkey->len - mod.ptr) return "RSA public key blob too short"; n_to_mpz(&rsa->e, exponent.ptr, exponent.len); n_to_mpz(&rsa->n, mod.ptr, mod.len); keyblobtoid(pubkey->ptr, pubkey->len, rsa->keyid, sizeof(rsa->keyid)); rsa->k = mpz_sizeinbase(&rsa->n, 2); /* size in bits, for a start */ rsa->k = (rsa->k + BITS_PER_BYTE - 1) / BITS_PER_BYTE; /* now octets */ if (rsa->k != mod.len) { mpz_clear(&rsa->e); mpz_clear(&rsa->n); return "RSA modulus shorter than specified"; } return NULL; }
/* * Processing FOR KE values. */ void unpack_KE(struct state *st , struct pluto_crypto_req *r , chunk_t *g) { struct pcr_kenonce *kn = &r->pcr_d.kn; if (!st->st_sec_in_use) { st->st_sec_in_use = TRUE; freeanychunk(*g); /* happens in odd error cases */ clonetochunk(*g, wire_chunk_ptr(kn, &(kn->gi)) , kn->gi.len, "saved gi value"); #ifdef HAVE_LIBNSS DBG(DBG_CRYPT, DBG_log("saving DH priv (local secret) and pub key into state struc")); clonetochunk(st->st_sec_chunk , wire_chunk_ptr(kn, &(kn->secret)) , kn->secret.len, "pointer to DH private key (secret)"); clonetochunk(st->pubk , wire_chunk_ptr(kn, &(kn->pubk)) , kn->pubk.len, "pointer to DH public key"); #else n_to_mpz(&st->st_sec , wire_chunk_ptr(kn, &(kn->secret)) , kn->secret.len); clonetochunk(st->st_sec_chunk , wire_chunk_ptr(kn, &(kn->secret)) , kn->secret.len, "long term secret"); #endif } }
/** Compute DH shared secret from our local secret and the peer's public value. * We make the leap that the length should be that of the group * (see quoted passage at start of ACCEPT_KE). */ static void calc_dh_shared(chunk_t *shared, const chunk_t g , const MP_INT *sec , const struct oakley_group_desc *group) { MP_INT mp_g, mp_shared; struct timeval tv0, tv1; unsigned long tv_diff; gettimeofday(&tv0, NULL); n_to_mpz(&mp_g, g.ptr, g.len); mpz_init(&mp_shared); mpz_powm(&mp_shared, &mp_g, sec, group->modulus); mpz_clear(&mp_g); *shared = mpz_to_n(&mp_shared, group->bytes); mpz_clear(&mp_shared); gettimeofday(&tv1, NULL); tv_diff=(tv1.tv_sec - tv0.tv_sec) * 1000000 + (tv1.tv_usec - tv0.tv_usec); DBG(DBG_CRYPT, DBG_log("calc_dh_shared(): time elapsed (%s): %ld usec" , enum_show(&oakley_group_names, group->group) , tv_diff); );
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); }
/* * Processing FOR KE values. */ void unpack_KE(struct state *st , struct pluto_crypto_req *r , chunk_t *g) { struct pcr_kenonce *kn = &r->pcr_d.kn; if (!st->st_sec_in_use) { st->st_sec_in_use = TRUE; freeanychunk(*g); /* happens in odd error cases */ clonetochunk(*g, wire_chunk_ptr(kn, &(kn->gi)) , kn->gi.len, "saved gi value"); n_to_mpz(&st->st_sec , wire_chunk_ptr(kn, &(kn->secret)) , kn->secret.len); clonetochunk(st->st_sec_chunk , wire_chunk_ptr(kn, &(kn->secret)) , kn->secret.len, "long term secret"); } }
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); );
void calc_ke(struct pluto_crypto_req *r) { #ifndef HAVE_LIBNSS MP_INT mp_g; MP_INT secret; chunk_t gi; #else chunk_t prime; chunk_t base; SECKEYDHParams dhp; PK11SlotInfo *slot = NULL; SECKEYPrivateKey *privk; SECKEYPublicKey *pubk; #endif struct pcr_kenonce *kn = &r->pcr_d.kn; const struct oakley_group_desc *group; group = lookup_group(kn->oakley_group); #ifndef HAVE_LIBNSS 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); #ifdef USE_MODP_RFC5114 oswcrypto.mod_exp(&mp_g, group->generator, &secret, group->modulus); #else oswcrypto.mod_exp(&mp_g, &groupgenerator, &secret, group->modulus); #endif 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); #else #ifdef USE_MODP_RFC5114 base = mpz_to_n2(group->generator); #else base = mpz_to_n2(&groupgenerator); #endif 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); #endif }