📄 ipsec_doi.c
字号:
} /* actual exponentiation; see PKCS#1 v2.0 5.1 */ { chunk_t temp_s; mpz_t c; n_to_mpz(c, sig_val, sig_len); mpz_powm(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); } /* sanity check on signature: see if it matches * PKCS#1 v1.5 8.1 encryption-block formatting */ { err_t ugh = NULL; if (s[0] != 0x00) ugh = "2" "no leading 00"; else if (hash_in_s[-1] != 0x00) ugh = "3" "00 separator not present"; else if (s[1] == 0x01) { const u_char *p; for (p = &s[2]; p != hash_in_s - 1; p++) { if (*p != 0xFF) { ugh = "4" "invalid Padding String"; break; } } } else if (s[1] == 0x02) { const u_char *p; for (p = &s[2]; p != hash_in_s - 1; p++) { if (*p == 0x00) { ugh = "5" "invalid Padding String"; break; } } } else ugh = "6" "Block Type not 01 or 02"; if (ugh != NULL) { /* note: it might be a good idea to make sure that * an observer cannot tell what kind of failure happened. * I don't know what this means in practice. */ /* We probably selected the wrong public key for peer: * SIG Payload decrypted into malformed ECB */ /* XXX notification: INVALID_KEY_INFORMATION */ return ugh; } } /* We have the decoded hash: see if it matches. */ if (memcmp(hash_val, hash_in_s, hash_len) != 0) { /* good: header, hash, signature, and other payloads well-formed * good: we could find an RSA Sig key for the peer. * bad: hash doesn't match * Guess: sides disagree about key to be used. */ DBG_cond_dump(DBG_CRYPT, "decrypted SIG", s, sig_len); DBG_cond_dump(DBG_CRYPT, "computed HASH", hash_val, hash_len); /* XXX notification: INVALID_HASH_INFORMATION */ return "9" "authentication failure: received SIG does not match computed HASH, but message is well-formed"; } /* Success: copy successful key into state. * There might be an old one if we previously aborted this * state transition. */ unreference_key(&st->st_peer_pubkey); st->st_peer_pubkey = reference_key(kr); return NULL; /* happy happy */}/* Check signature against all RSA public keys we can find. * If we need keys from DNS KEY records, and they haven't been fetched, * return STF_SUSPEND to ask for asynch DNS lookup. * * Note: parameter keys_from_dns contains results of DNS lookup for key * or is NULL indicating lookup not yet tried. * * take_a_crack is a helper function. Mostly forensic. * If only we had coroutines. */struct tac_state { /* RSA_check_signature's args that take_a_crack needs */ struct state *st; const u_char *hash_val; size_t hash_len; const pb_stream *sig_pbs; /* state carried between calls */ err_t best_ugh; /* most successful failure */ int tried_cnt; /* number of keys tried */ char tried[50]; /* keyids of tried public keys */ char *tn; /* roof of tried[] */};static booltake_a_crack(struct tac_state *s, struct pubkey *kr, const char *story USED_BY_DEBUG){ err_t ugh = try_RSA_signature(s->hash_val, s->hash_len, s->sig_pbs , kr, s->st); const struct RSA_public_key *k = &kr->u.rsa; s->tried_cnt++; if (ugh == NULL) { DBG(DBG_CRYPT | DBG_CONTROL , DBG_log("an RSA Sig check passed with *%s [%s]" , k->keyid, story)); return TRUE; } else { DBG(DBG_CRYPT , DBG_log("an RSA Sig check failure %s with *%s [%s]" , ugh + 1, k->keyid, story)); if (s->best_ugh == NULL || s->best_ugh[0] < ugh[0]) s->best_ugh = ugh; if (ugh[0] > '0' && s->tn - s->tried + KEYID_BUF + 2 < (ptrdiff_t)sizeof(s->tried)) { strcpy(s->tn, " *"); strcpy(s->tn + 2, k->keyid); s->tn += strlen(s->tn); } return FALSE; }}static stf_statusRSA_check_signature(struct state *st, const u_char hash_val[MAX_DIGEST_LEN], size_t hash_len, const pb_stream *sig_pbs#ifdef USE_KEYRR, const struct pubkey_list *keys_from_dns#endif /* USE_KEYRR */, const struct gw_info *gateways_from_dns){ const struct connection *c = st->st_connection; struct tac_state s; err_t dns_ugh = NULL; s.st = st; s.hash_val = hash_val; s.hash_len = hash_len; s.sig_pbs = sig_pbs; s.best_ugh = NULL; s.tried_cnt = 0; s.tn = s.tried; /* try all gateway records hung off c */ if ((c->policy & POLICY_OPPO)) { struct gw_info *gw; for (gw = c->gw_info; gw != NULL; gw = gw->next) { /* only consider entries that have a key and are for our peer */ if (gw->gw_key_present && same_id(&gw->gw_id, &c->spd.that.id) && take_a_crack(&s, gw->key, "key saved from DNS TXT")) return STF_OK; } } /* try all appropriate Public keys */ { struct pubkey_list *p, **pp; int pathlen; pp = &pubkeys; pathlen = pathlen; /* make sure it used even with !X509 */ { char buf[IDTOA_BUF]; DBG(DBG_CONTROL, dntoa_or_null(buf, IDTOA_BUF, c->spd.that.ca, "%any"); DBG_log("required CA is '%s'", buf)); } for (p = pubkeys; p != NULL; p = *pp) { struct pubkey *key = p->key; if (key->alg == PUBKEY_ALG_RSA && same_id(&c->spd.that.id, &key->id) && trusted_ca(key->issuer, c->spd.that.ca, &pathlen)) { time_t now; { char buf[IDTOA_BUF]; DBG(DBG_CONTROL, dntoa_or_null(buf, IDTOA_BUF, key->issuer, "%any"); DBG_log("key issuer CA is '%s'", buf)); } /* check if found public key has expired */ time(&now); if (key->until_time != UNDEFINED_TIME && key->until_time < now) { loglog(RC_LOG_SERIOUS, "cached RSA public key has expired and has been deleted"); *pp = free_public_keyentry(p); continue; /* continue with next public key */ } if (take_a_crack(&s, key, "preloaded key")) return STF_OK; } pp = &p->next; } } /* if no key was found (evidenced by best_ugh == NULL) * and that side of connection is key_from_DNS_on_demand * then go search DNS for keys for peer. */ if (s.best_ugh == NULL && c->spd.that.key_from_DNS_on_demand) { if (gateways_from_dns != NULL) { /* TXT keys */ const struct gw_info *gwp; for (gwp = gateways_from_dns; gwp != NULL; gwp = gwp->next) if (gwp->gw_key_present && take_a_crack(&s, gwp->key, "key from DNS TXT")) return STF_OK; }#ifdef USE_KEYRR else if (keys_from_dns != NULL) { /* KEY keys */ const struct pubkey_list *kr; for (kr = keys_from_dns; kr != NULL; kr = kr->next) if (kr->key->alg == PUBKEY_ALG_RSA && take_a_crack(&s, kr->key, "key from DNS KEY")) return STF_OK; }#endif /* USE_KEYRR */ else { /* nothing yet: ask for asynch DNS lookup */ return STF_SUSPEND; } } /* no acceptable key was found: diagnose */ { char id_buf[IDTOA_BUF]; /* arbitrary limit on length of ID reported */ (void) idtoa(&st->st_connection->spd.that.id, id_buf, sizeof(id_buf)); if (s.best_ugh == NULL) { if (dns_ugh == NULL) loglog(RC_LOG_SERIOUS, "no RSA public key known for '%s'" , id_buf); else loglog(RC_LOG_SERIOUS, "no RSA public key known for '%s'" "; DNS search for KEY failed (%s)" , id_buf, dns_ugh); /* ??? is this the best code there is? */ return STF_FAIL + INVALID_KEY_INFORMATION; } if (s.best_ugh[0] == '9') { loglog(RC_LOG_SERIOUS, "%s", s.best_ugh + 1); /* XXX Could send notification back */ return STF_FAIL + INVALID_HASH_INFORMATION; } else { if (s.tried_cnt == 1) { loglog(RC_LOG_SERIOUS , "Signature check (on %s) failed (wrong key?); tried%s" , id_buf, s.tried); DBG(DBG_CONTROL, DBG_log("public key for %s failed:" " decrypted SIG payload into a malformed ECB (%s)" , id_buf, s.best_ugh + 1)); } else { loglog(RC_LOG_SERIOUS , "Signature check (on %s) failed:" " tried%s keys but none worked." , id_buf, s.tried); DBG(DBG_CONTROL, DBG_log("all %d public keys for %s failed:" " best decrypted SIG payload into a malformed ECB (%s)" , s.tried_cnt, id_buf, s.best_ugh + 1)); } return STF_FAIL + INVALID_KEY_INFORMATION; } }}static notification_taccept_nonce(struct msg_digest *md, chunk_t *dest, const char *name){ pb_stream *nonce_pbs = &md->chain[ISAKMP_NEXT_NONCE]->pbs; size_t len = pbs_left(nonce_pbs); if (len < MINIMUM_NONCE_SIZE || MAXIMUM_NONCE_SIZE < len) { loglog(RC_LOG_SERIOUS, "%s length not between %d and %d" , name , MINIMUM_NONCE_SIZE, MAXIMUM_NONCE_SIZE); return PAYLOAD_MALFORMED; /* ??? */ } clonereplacechunk(*dest, nonce_pbs->cur, len, "nonce"); return NOTHING_WRONG;}/* encrypt message, sans fixed part of header * IV is fetched from st->st_new_iv and stored into st->st_iv. * The theory is that there will be no "backing out", so we commit to IV. * We also close the pbs. */boolencrypt_message(pb_stream *pbs, struct state *st){ const struct encrypt_desc *e = st->st_oakley.encrypter; u_int8_t *enc_start = pbs->start + sizeof(struct isakmp_hdr); size_t enc_len = pbs_offset(pbs) - sizeof(struct isakmp_hdr); DBG_cond_dump(DBG_CRYPT | DBG_RAW, "encrypting:\n", enc_start, enc_len); /* Pad up to multiple of encryption blocksize. * See the description associated with the definition of * struct isakmp_hdr in packet.h. */ { size_t padding = pad_up(enc_len, e->enc_blocksize); if (padding != 0) { if (!out_zero(padding, pbs, "encryption padding")) return FALSE; enc_len += padding; } } DBG(DBG_CRYPT, DBG_log("encrypting using %s", enum_show(&oakley_enc_names, st->st_oakley.encrypt))); /* e->crypt(TRUE, enc_start, enc_len, st); */ crypto_cbc_encrypt(e, TRUE, enc_start, enc_len, st); update_iv(st); DBG_cond_dump(DBG_CRYPT, "next IV:", st->st_iv, st->st_iv_len); close_message(pbs); return TRUE;}/* Compute HASH(1), HASH(2) of Quick Mode. * HASH(1) is part of Quick I1 message. * HASH(2) is part of Quick R1 message. * Used by: quick_outI1, quick_inI1_outR1 (twice), quick_inR1_outI2 * (see RFC 2409 "IKE" 5.5, pg. 18 or draft-ietf-ipsec-ike-01.txt 6.2 pg 25) */static size_tquick_mode_hash12(u_char *dest, const u_char *start, const u_char *roof, const struct state *st, const msgid_t *msgid, bool hash2){ struct hmac_ctx ctx;#if 0 /* if desperate to debug hashing */# define hmac_update(ctx, ptr, len) { \ DBG_dump("hash input", (ptr), (len)); \ (hmac_update)((ctx), (ptr), (len)); \ } DBG_dump("hash key", st->st_skeyid_a.ptr, st->st_skeyid_a.len);#endif hmac_init_chunk(&ctx, st->st_oakley.hasher, st->st_skeyid_a); hmac_update(&ctx, (const void *) msgid, sizeof(msgid_t)); if (hash2) hmac_update_chunk(&ctx, st->st_ni); /* include Ni_b in the hash */ hmac_update(&ctx, start, roof-start); hmac_final(dest, &ctx); DBG(DBG_CRYPT, DBG_log("HASH(%d) computed:", hash2 + 1); DBG_dump("", dest, ctx.hmac_digest_len)); return ctx.hmac_digest_len;# undef hmac_update}/* Compute HASH(3) in Quick Mode (part of Quick I2 message). * Used by: quick_inR1_outI2, quick_inI2 * See RFC2409 "The Internet Key Exchange (IKE)" 5.5. * NOTE: this hash (unlike HASH(1) and HASH(2)) ONLY covers the * Message ID and Nonces. This is a mistake. */static size_tquick_mode_hash3(u_char *dest, struct state *st){ struct hmac_ctx ctx; hmac_init_chunk(&ctx, st->st_oakley.hasher, st->st_skeyid_a); hmac_update(&ctx, "\0", 1); hmac_update(&ctx, (u_char *) &st->st_msgid, sizeof(st->st_msgid)); hmac_update_chunk(&ctx, st->st_ni); hmac_update_chunk(&ctx, st->st_nr); hmac_final(dest, &ctx); DBG_cond_dump(DBG_CRYPT, "HASH(3) computed:", dest, ctx.hmac_digest_len); return ctx.hmac_digest_len;}/* Compute Phase 2 IV. * Uses Phase 1 IV from st_iv; puts result in st_new_iv. */voidinit_phase2_iv(struct state *st, const msgid_t *msgid){ const struct hash_desc *h = st->st_oakley.hasher; union hash_ctx ctx; DBG_cond_dump(DBG_CRYPT, "last Phase 1 IV:" , st->st_ph1_iv, st->st_ph1_iv_len); st->st_new_iv_len = h->hash_digest_len; passert(st->st_new_iv_len <= sizeof(st->st_new_iv)); DBG_cond_dump(DBG_CRYPT, "last Phase 1 IV:" , st->st_iv, st->st_iv_len); h->hash_init(&ctx); h->hash_update(&ctx, st->st_ph1_iv, st->st_ph1_iv_len); passert(*msgid != 0); h->hash_update(&ctx, (const u_char *)msgid, sizeof(*msgid)); h->hash_final(st->st_new_iv, &ctx); DBG_cond_dump(DBG_CRYPT, "computed Ph
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -