📄 keys.c
字号:
/* mechanisms for preshared keys (public, private, and preshared secrets) * Copyright (C) 1998-2001 D. Hugh Redelmeier. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * RCSID $Id: keys.c,v 1.97 2004/10/21 19:08:29 mcr Exp $ */#include <stddef.h>#include <stdlib.h>#include <string.h>#include <ctype.h>#include <unistd.h>#include <errno.h>#include <time.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <resolv.h>#include <arpa/nameser.h> /* missing from <resolv.h> on old systems */#include <sys/queue.h>#include <glob.h>#ifndef GLOB_ABORTED# define GLOB_ABORTED GLOB_ABEND /* fix for old versions */#endif#include <openswan.h>#include <openswan/ipsec_policy.h>#include "constants.h"#include "defs.h"#include "id.h"#include "x509.h"#include "pgp.h"#include "certs.h"#include "smartcard.h"#ifdef XAUTH_USEPAM#include <security/pam_appl.h>#endif#include "connections.h" /* needs id.h */#include "state.h"#include "lex.h"#include "keys.h"#include "adns.h" /* needs <resolv.h> */#include "dnskey.h" /* needs keys.h and adns.h */#include "log.h"#include "whack.h" /* for RC_LOG_SERIOUS */#include "timer.h"#include "fetch.h"#include "x509more.h"/* Maximum length of filename and passphrase buffer */#define BUF_LEN 256#ifdef NAT_TRAVERSAL#define PB_STREAM_UNDEFINED#include "nat_traversal.h"#endifstruct fld { const char *name; size_t offset;};static const struct fld RSA_private_field[] ={ { "Modulus", offsetof(struct RSA_private_key, pub.n) }, { "PublicExponent", offsetof(struct RSA_private_key, pub.e) }, { "PrivateExponent", offsetof(struct RSA_private_key, d) }, { "Prime1", offsetof(struct RSA_private_key, p) }, { "Prime2", offsetof(struct RSA_private_key, q) }, { "Exponent1", offsetof(struct RSA_private_key, dP) }, { "Exponent2", offsetof(struct RSA_private_key, dQ) }, { "Coefficient", offsetof(struct RSA_private_key, qInv) },};#ifdef DEBUGstatic voidRSA_show_key_fields(struct RSA_private_key *k, int fieldcnt){ const struct fld *p; DBG_log(" keyid: *%s", k->pub.keyid); for (p = RSA_private_field; p < &RSA_private_field[fieldcnt]; p++) { MP_INT *n = (MP_INT *) ((char *)k + p->offset); size_t sz = mpz_sizeinbase(n, 16); char buf[RSA_MAX_OCTETS * 2 + 2]; /* ought to be big enough */ passert(sz <= sizeof(buf)); mpz_get_str(buf, 16, n); DBG_log(" %s: %s", p->name, buf); }}/* debugging info that compromises security! */static voidRSA_show_private_key(struct RSA_private_key *k){ RSA_show_key_fields(k, elemsof(RSA_private_field));}static voidRSA_show_public_key(struct RSA_public_key *k){ /* Kludge: pretend that it is a private key, but only display the * first two fields (which are the public key). */ passert(offsetof(struct RSA_private_key, pub) == 0); RSA_show_key_fields((struct RSA_private_key *)k, 2);}#endifstatic const char *RSA_private_key_sanity(struct RSA_private_key *k){ /* note that the *last* error found is reported */ err_t ugh = NULL; mpz_t t, u, q1;#ifdef DEBUG /* debugging info that compromises security */ DBG(DBG_PRIVATE, RSA_show_private_key(k));#endif /* PKCS#1 1.5 section 6 requires modulus to have at least 12 octets. * We actually require more (for security). */ if (k->pub.k < RSA_MIN_OCTETS) return RSA_MIN_OCTETS_UGH; /* we picked a max modulus size to simplify buffer allocation */ if (k->pub.k > RSA_MAX_OCTETS) return RSA_MAX_OCTETS_UGH; mpz_init(t); mpz_init(u); mpz_init(q1); /* check that n == p * q */ mpz_mul(u, &k->p, &k->q); if (mpz_cmp(u, &k->pub.n) != 0) ugh = "n != p * q"; /* check that e divides neither p-1 nor q-1 */ mpz_sub_ui(t, &k->p, 1); mpz_mod(t, t, &k->pub.e); if (mpz_cmp_ui(t, 0) == 0) ugh = "e divides p-1"; mpz_sub_ui(t, &k->q, 1); mpz_mod(t, t, &k->pub.e); if (mpz_cmp_ui(t, 0) == 0) ugh = "e divides q-1"; /* check that d is e^-1 (mod lcm(p-1, q-1)) */ /* see PKCS#1v2, aka RFC 2437, for the "lcm" */ mpz_sub_ui(q1, &k->q, 1); mpz_sub_ui(u, &k->p, 1); mpz_gcd(t, u, q1); /* t := gcd(p-1, q-1) */ mpz_mul(u, u, q1); /* u := (p-1) * (q-1) */ mpz_divexact(u, u, t); /* u := lcm(p-1, q-1) */ mpz_mul(t, &k->d, &k->pub.e); mpz_mod(t, t, u); if (mpz_cmp_ui(t, 1) != 0) ugh = "(d * e) mod (lcm(p-1, q-1)) != 1"; /* check that dP is d mod (p-1) */ mpz_sub_ui(u, &k->p, 1); mpz_mod(t, &k->d, u); if (mpz_cmp(t, &k->dP) != 0) ugh = "dP is not congruent to d mod (p-1)"; /* check that dQ is d mod (q-1) */ mpz_sub_ui(u, &k->q, 1); mpz_mod(t, &k->d, u); if (mpz_cmp(t, &k->dQ) != 0) ugh = "dQ is not congruent to d mod (q-1)"; /* check that qInv is (q^-1) mod p */ mpz_mul(t, &k->qInv, &k->q); mpz_mod(t, t, &k->p); if (mpz_cmp_ui(t, 1) != 0) ugh = "qInv is not conguent ot (q^-1) mod p"; mpz_clear(t); mpz_clear(u); mpz_clear(q1); return ugh;}/* * compute an RSA signature with PKCS#1 padding */voidsign_hash(const struct RSA_private_key *k, const u_char *hash_val, size_t hash_len , u_char *sig_val, size_t sig_len){ chunk_t ch; mpz_t t1, t2; size_t padlen; u_char *p = sig_val; DBG(DBG_CONTROL | DBG_CRYPT, DBG_log("signing hash with RSA Key *%s", k->pub.keyid) ) /* PKCS#1 v1.5 8.1 encryption-block formatting */ *p++ = 0x00; *p++ = 0x01; /* BT (block type) 01 */ padlen = sig_len - 3 - hash_len; memset(p, 0xFF, padlen); p += padlen; *p++ = 0x00; memcpy(p, hash_val, hash_len); passert(p + hash_len - sig_val == (ptrdiff_t)sig_len); /* PKCS#1 v1.5 8.2 octet-string-to-integer conversion */ n_to_mpz(t1, sig_val, sig_len); /* (could skip leading 0x00) */ /* PKCS#1 v1.5 8.3 RSA computation y = x^c mod n * Better described in PKCS#1 v2.0 5.1 RSADP. * There are two methods, depending on the form of the private key. * We use the one based on the Chinese Remainder Theorem. */ mpz_init(t2); mpz_powm(t2, t1, &k->dP, &k->p); /* m1 = c^dP mod p */ mpz_powm(t1, t1, &k->dQ, &k->q); /* m2 = c^dQ mod Q */ mpz_sub(t2, t2, t1); /* h = qInv (m1 - m2) mod p */ mpz_mod(t2, t2, &k->p); mpz_mul(t2, t2, &k->qInv); mpz_mod(t2, t2, &k->p); mpz_mul(t2, t2, &k->q); /* m = m2 + h q */ mpz_add(t1, t1, t2); /* PKCS#1 v1.5 8.4 integer-to-octet-string conversion */ ch = mpz_to_n(t1, sig_len); memcpy(sig_val, ch.ptr, sig_len); pfree(ch.ptr); mpz_clear(t1); mpz_clear(t2);}const char *shared_secrets_file = SHARED_SECRETS_FILE;struct id_list { struct id id; struct id_list *next;};struct secret { struct id_list *ids; int secretlineno; enum PrivateKeyKind kind; union { chunk_t preshared_secret; struct RSA_private_key RSA_private_key; smartcard_t *smartcard; } u; struct secret *next;};/* * forms the keyid from the public exponent e and modulus n */voidform_keyid(chunk_t e, chunk_t n, char* keyid, unsigned *keysize){ /* eliminate leading zero byte in modulus from ASN.1 coding */ if (*n.ptr == 0x00) { n.ptr++; n.len--; } /* form the FreeS/WAN keyid */ keyid[0] = '\0'; /* in case of splitkeytoid failure */ splitkeytoid(e.ptr, e.len, n.ptr, n.len, keyid, KEYID_BUF); /* return the RSA modulus size in octets */ *keysize = n.len;}struct pubkey*allocate_RSA_public_key(const cert_t cert){ struct pubkey *pk = alloc_thing(struct pubkey, "pubkey"); chunk_t e, n; switch (cert.type) { case CERT_PGP: e = cert.u.pgp->publicExponent; n = cert.u.pgp->modulus; break; case CERT_X509_SIGNATURE: e = cert.u.x509->publicExponent; n = cert.u.x509->modulus; break; default: openswan_log("RSA public key allocation error"); return NULL; } n_to_mpz(&pk->u.rsa.e, e.ptr, e.len); n_to_mpz(&pk->u.rsa.n, n.ptr, n.len); form_keyid(e, n, pk->u.rsa.keyid, &pk->u.rsa.k);#ifdef DEBUG DBG(DBG_PRIVATE, RSA_show_public_key(&pk->u.rsa));#endif pk->alg = PUBKEY_ALG_RSA; pk->id = empty_id; pk->issuer = empty_chunk; return pk;}/* * free a public key struct */voidfree_public_key(struct pubkey *pk){ free_id_content(&pk->id); freeanychunk(pk->issuer); /* algorithm-specific freeing */ switch (pk->alg) { case PUBKEY_ALG_RSA: free_RSA_public_content(&pk->u.rsa); break; default: bad_case(pk->alg); } pfree(pk);}struct secret *secrets = NULL;/* find the struct secret associated with the combination of * me and the peer. We match the Id (if none, the IP address). * Failure is indicated by a NULL. */static const struct secret *get_secret(const struct connection *c, enum PrivateKeyKind kind, bool asym){ enum { /* bits */ match_default = 01, match_him = 02, match_me = 04 }; unsigned char idstr1[IDTOA_BUF], idme[IDTOA_BUF] , idhim[IDTOA_BUF], idhim2[IDTOA_BUF]; unsigned int best_match = 0; struct secret *best = NULL; struct secret *s; const struct id *my_id = &c->spd.this.id , *his_id = &c->spd.that.id; struct id rw_id; idtoa(my_id, idme, IDTOA_BUF); idtoa(his_id, idhim, IDTOA_BUF); strcpy(idhim2, idhim); DBG(DBG_CONTROL, DBG_log("started looking for secret for %s->%s of kind %s" , idme, idhim , enum_name(&ppk_names, kind))); /* is there a certificate assigned to this connection? */ if (kind == PPK_RSA && c->spd.this.sendcert != cert_forcedtype && (c->spd.this.cert.type == CERT_X509_SIGNATURE || c->spd.this.cert.type == CERT_PKCS7_WRAPPED_X509 || c->spd.this.cert.type == CERT_PGP)) { struct pubkey *my_public_key = allocate_RSA_public_key(c->spd.this.cert); passert(my_public_key != NULL); for (s = secrets; s != NULL; s = s->next) { DBG(DBG_CONTROL, DBG_log("searching for certificate %s:%s vs %s:%s" , enum_name(&ppk_names, s->kind) , s->u.RSA_private_key.pub.keyid , enum_name(&ppk_names, kind) , my_public_key->u.rsa.keyid) ); if (s->kind == kind && same_RSA_public_key(&s->u.RSA_private_key.pub , &my_public_key->u.rsa)) { best = s; break; /* we have found the private key - no sense in searching further */ } } free_public_key(my_public_key); return best; } if (his_id_was_instantiated(c) && !(c->policy&AGGRESSIVE)) { DBG(DBG_CONTROL, DBG_log("instantiating him to 0.0.0.0")); /* roadwarrior: replace him with 0.0.0.0 */ rw_id.kind = addrtypeof(&c->spd.that.host_addr) == AF_INET ? ID_IPV4_ADDR : ID_IPV6_ADDR; happy(anyaddr(addrtypeof(&c->spd.that.host_addr), &rw_id.ip_addr)); his_id = &rw_id; idtoa(his_id, idhim2, IDTOA_BUF); }#ifdef NAT_TRAVERSAL else if ((nat_traversal_enabled) && (c->policy & POLICY_PSK) && (kind == PPK_PSK) && (((c->kind == CK_TEMPLATE) && (c->spd.that.id.kind == ID_NONE)) || ((c->kind == CK_INSTANCE) && (id_is_ipaddr(&c->spd.that.id))))) { DBG(DBG_CONTROL, DBG_log("replace him to 0.0.0.0")); /* roadwarrior: replace him with 0.0.0.0 */ rw_id.kind = ID_IPV4_ADDR; happy(anyaddr(addrtypeof(&c->spd.that.host_addr), &rw_id.ip_addr)); his_id = &rw_id; idtoa(his_id, idhim2, IDTOA_BUF); }#endif DBG(DBG_CONTROL, DBG_log("actually looking for secret for %s->%s of kind %s" , idme, idhim2 , enum_name(&ppk_names, kind))); for (s = secrets; s != NULL; s = s->next) { if (s->kind == kind) { unsigned int match = 0; if (s->ids == NULL) { /* a default (signified by lack of ids): * accept if no more specific match found */ match = match_default; } else { /* check if both ends match ids */ struct id_list *i; int idnum = 0; for (i = s->ids; i != NULL; i = i->next) { idnum++; idtoa(&i->id, idstr1, IDTOA_BUF); if (same_id(my_id, &i->id)) match |= match_me; if (same_id(his_id, &i->id)) match |= match_him; DBG(DBG_CONTROL, DBG_log("%d: compared PSK %s to %s / %s -> %d", idnum, idstr1, idme, idhim, match)); } /* If our end matched the only id in the list, * default to matching any peer. * A more specific match will trump this. */ if (match == match_me && s->ids->next == NULL) match |= match_default; } switch (match) { case match_me: /* if this is an asymmetric (eg. public key) system, * allow this-side-only match to count, even if * there are other ids in the list. */ if (!asym) break; /* FALLTHROUGH */ case match_default: /* default all */ case match_me | match_default: /* default peer */ case match_me | match_him: /* explicit */ if (match == best_match) { /* two good matches are equally good: * do they agree? */ bool same; switch (kind) { case PPK_PSK: same = s->u.preshared_secret.len == best->u.preshared_secret.len && memcmp(s->u.preshared_secret.ptr , best->u.preshared_secret.ptr , s->u.preshared_secret.len) == 0; break; case PPK_RSA: /* Dirty trick: since we have code to compare * RSA public keys, but not private keys, we * make the assumption that equal public keys * mean equal private keys. This ought to work. */ same = same_RSA_public_key(&s->u.RSA_private_key.pub , &best->u.RSA_private_key.pub); break; default: bad_case(kind); } if (!same) { loglog(RC_LOG_SERIOUS, "multiple ipsec.secrets entries with distinct secrets match endpoints:" " first secret used");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -