/* 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; }
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); }
/* build an ocsp location from certificate information * without unsharing its contents */ static bool build_ocsp_location(const x509cert_t *cert, ocsp_location_t *location) { static u_char digest[SHA1_DIGEST_SIZE]; /* temporary storage */ location->uri = (cert->accessLocation.ptr != NULL) ? cert->accessLocation : ocsp_default_uri; /* abort if no ocsp location uri is defined */ if (location->uri.ptr == NULL) return FALSE; setchunk(location->authNameID, digest, SHA1_DIGEST_SIZE); compute_digest(cert->issuer, OID_SHA1, &location->authNameID); location->next = NULL; location->issuer = cert->issuer; location->authKeyID = cert->authKeyID; location->authKeySerialNumber = cert->authKeySerialNumber; if (cert->authKeyID.ptr == NULL) { x509cert_t *authcert = get_authcert(cert->issuer , cert->authKeySerialNumber, cert->authKeyID, AUTH_CA); if (authcert != NULL) { location->authKeyID = authcert->subjectKeyID; location->authKeySerialNumber = authcert->serialNumber; } } location->nonce = empty_chunk; location->certinfo = NULL; return TRUE; }
void ikev2_derive_child_keys(struct state *st, enum phase1_role role) { struct v2prf_stuff childsacalc; chunk_t ikeymat,rkeymat; struct ipsec_proto_info *ipi = &st->st_esp; ipi->attrs.transattrs.ei=kernel_alg_esp_info( ipi->attrs.transattrs.encrypt, ipi->attrs.transattrs.enckeylen, ipi->attrs.transattrs.integ_hash); passert(ipi->attrs.transattrs.ei != NULL); memset(&childsacalc, 0, sizeof(childsacalc)); childsacalc.prf_hasher = st->st_oakley.prf_hasher; setchunk(childsacalc.ni, st->st_ni.ptr, st->st_ni.len); setchunk(childsacalc.nr, st->st_nr.ptr, st->st_nr.len); childsacalc.spii.len=0; childsacalc.spir.len=0; childsacalc.counter[0] = 1; childsacalc.skeyseed = &st->st_skey_d; st->st_esp.present = TRUE; st->st_esp.keymat_len = st->st_esp.attrs.transattrs.ei->enckeylen+ st->st_esp.attrs.transattrs.ei->authkeylen; /* * * Keying material MUST be taken from the expanded KEYMAT in the * following order: * * All keys for SAs carrying data from the initiator to the responder * are taken before SAs going in the reverse direction. * * If multiple IPsec protocols are negotiated, keying material is * taken in the order in which the protocol headers will appear in * the encapsulated packet. * * If a single protocol has both encryption and authentication keys, * the encryption key is taken from the first octets of KEYMAT and * the authentication key is taken from the next octets. * */ v2genbytes(&ikeymat, st->st_esp.keymat_len , "initiator keys", &childsacalc); v2genbytes(&rkeymat, st->st_esp.keymat_len , "responder keys", &childsacalc); /* This should really be role == INITIATOR, but then our keys are * installed reversed. This is a workaround until we locate the * real problem. It's better not to release copies of our code * that will be incompatible with everything else, including our * own updated version * Found by Herbert Xu * if(role == INITIATOR) { */ if(role != INITIATOR) { DBG(DBG_CRYPT, DBG_dump_chunk("our keymat", ikeymat); DBG_dump_chunk("peer keymat", rkeymat); );
void ikev2_derive_child_keys(struct state *st, enum original_role role) { chunk_t ikeymat, rkeymat; /* ??? note assumption that AH and ESP cannot be combined */ struct ipsec_proto_info *ipi = st->st_esp.present? &st->st_esp : st->st_ah.present? &st->st_ah : NULL; struct esp_info *ei; passert(ipi != NULL); /* ESP or AH must be present */ passert(st->st_esp.present != st->st_ah.present); /* only one */ /* ??? there is no kernel_alg_ah_info */ /* ??? will this work if the result of kernel_alg_esp_info * is a pointer into its own static buffer (therefore ephemeral)? */ ei = kernel_alg_esp_info( ipi->attrs.transattrs.encrypt, ipi->attrs.transattrs.enckeylen, ipi->attrs.transattrs.integ_hash); passert(ei != NULL); ipi->attrs.transattrs.ei = ei; /* ipi->attrs.transattrs.integ_hasher->hash_key_size / BITS_PER_BYTE; */ unsigned authkeylen = ikev1_auth_kernel_attrs(ei->auth, NULL); /* ??? no account is taken of AH */ /* transid is same as esp_ealg_id */ switch (ei->transid) { case IKEv2_ENCR_reserved: /* AH */ ipi->keymat_len = authkeylen; break; case IKEv2_ENCR_AES_CTR: ipi->keymat_len = ei->enckeylen + authkeylen + AES_CTR_SALT_BYTES;; break; case IKEv2_ENCR_AES_GCM_8: case IKEv2_ENCR_AES_GCM_12: case IKEv2_ENCR_AES_GCM_16: /* aes_gcm does not use an integ (auth) algo - see RFC 4106 */ ipi->keymat_len = ei->enckeylen + AES_GCM_SALT_BYTES; break; case IKEv2_ENCR_AES_CCM_8: case IKEv2_ENCR_AES_CCM_12: case IKEv2_ENCR_AES_CCM_16: /* aes_ccm does not use an integ (auth) algo - see RFC 4309 */ ipi->keymat_len = ei->enckeylen + AES_CCM_SALT_BYTES; break; default: /* ordinary ESP */ ipi->keymat_len = ei->enckeylen + authkeylen; break; } DBG(DBG_CONTROL, DBG_log("enckeylen=%" PRIu32 ", authkeylen=%u, keymat_len=%" PRIu16, ei->enckeylen, authkeylen, ipi->keymat_len)); /* * * Keying material MUST be taken from the expanded KEYMAT in the * following order: * * All keys for SAs carrying data from the initiator to the responder * are taken before SAs going in the reverse direction. * * If multiple IPsec protocols are negotiated, keying material is * taken in the order in which the protocol headers will appear in * the encapsulated packet. * * If a single protocol has both encryption and authentication keys, * the encryption key is taken from the first octets of KEYMAT and * the authentication key is taken from the next octets. * * For AES GCM (RFC 4106 Section 8,1) we need to add 4 bytes for * salt (AES_GCM_SALT_BYTES) */ chunk_t ni; chunk_t nr; setchunk(ni, st->st_ni.ptr, st->st_ni.len); setchunk(nr, st->st_nr.ptr, st->st_nr.len); PK11SymKey *keymat = ikev2_child_sa_keymat(st->st_oakley.prf_hasher, st->st_skey_d_nss, NULL/*dh*/, ni, nr, ipi->keymat_len * 2); PK11SymKey *ikey = key_from_symkey_bytes(keymat, 0, ipi->keymat_len); ikeymat = chunk_from_symkey("initiator keys", ikey); free_any_symkey("ikey:", &ikey); PK11SymKey *rkey = key_from_symkey_bytes(keymat, ipi->keymat_len, ipi->keymat_len); rkeymat = chunk_from_symkey("responder keys:", rkey); free_any_symkey("rkey:", &rkey); free_any_symkey("keymat", &keymat); if (role != ORIGINAL_INITIATOR) { DBG(DBG_PRIVATE, { DBG_dump_chunk("our keymat", ikeymat); DBG_dump_chunk("peer keymat", rkeymat); });
stf_status ikev2_calc_no_ppk_auth(struct state *st, unsigned char *id_hash, chunk_t *no_ppk_auth /* output */) { struct connection *c = st->st_connection; enum keyword_authby authby = c->spd.this.authby; freeanychunk(*no_ppk_auth); /* in case it was occupied */ switch (authby) { case AUTH_RSASIG: { const struct asn1_hash_blob *h = NULL; if (st->st_hash_negotiated & NEGOTIATE_AUTH_HASH_SHA2_512) { h = &asn1_rsa_pss_sha2_512; } else if (st->st_hash_negotiated & NEGOTIATE_AUTH_HASH_SHA2_384) { h = &asn1_rsa_pss_sha2_384; } else if (st->st_hash_negotiated & NEGOTIATE_AUTH_HASH_SHA2_256) { h = &asn1_rsa_pss_sha2_256; } else if (c->sighash_policy & POL_SIGHASH_NONE) { /* RSA with SHA1 without Digsig: no oid blob appended */ if (!ikev2_calculate_rsa_hash(st, st->st_original_role, id_hash, NULL, no_ppk_auth, IKEv2_AUTH_HASH_SHA1)) { /* ??? what diagnostic? */ return STF_FAIL; } return STF_OK; } else { loglog(RC_LOG_SERIOUS, "No compatible hash algo"); return STF_FAIL; } chunk_t hashval; if (!ikev2_calculate_rsa_hash(st, st->st_original_role, id_hash, NULL, &hashval, h->hash_algo)) { /* ??? what diagnostic? */ return STF_FAIL; } if (st->st_seen_hashnotify) { /* * combine blobs to create no_ppk_auth: * - ASN.1 algo blob * - hashval */ int len = h->blob_sz + hashval.len; u_char *blobs = alloc_bytes(len, "bytes for blobs for AUTH_DIGSIG NO_PPK_AUTH"); memcpy(&blobs[0], h->blob, h->blob_sz); memcpy(&blobs[h->blob_sz], hashval.ptr, hashval.len); freeanychunk(hashval); setchunk(*no_ppk_auth, blobs, len); } return STF_OK; } case AUTH_PSK: /* store in no_ppk_auth */ if (!ikev2_create_psk_auth(AUTH_PSK, st, id_hash, no_ppk_auth)) { /* ??? what diagnostic? */ return STF_INTERNAL_ERROR; } return STF_OK; default: bad_case(authby); } }