📄 keys.c
字号:
best = s; /* list is backwards: take latest in list */ } } else if (match > best_match) { DBG(DBG_CONTROL, DBG_log("best_match %d>%d best=%p (line=%d)" , best_match, match , s, s->secretlineno)); /* this is the best match so far */ best_match = match; best = s; } else { DBG(DBG_CONTROL, DBG_log("match(%d) was not best_match(%d)" , match, best_match)); } } } } DBG(DBG_CONTROL, DBG_log("concluding with best_match=%d best=%p (lineno=%d)" , best_match, best, best? best->secretlineno : -1)); return best;}/* find the appropriate preshared key (see get_secret). * Failure is indicated by a NULL pointer. * Note: the result is not to be freed by the caller. */const chunk_t *get_preshared_secret(const struct connection *c){ const struct secret *s = get_secret(c, PPK_PSK, FALSE);#ifdef DEBUG DBG(DBG_PRIVATE, if (s == NULL) DBG_log("no Preshared Key Found"); else DBG_dump_chunk("Preshared Key", s->u.preshared_secret); );#endif return s == NULL? NULL : &s->u.preshared_secret;}/* check the existence of an RSA private key matching an RSA public * key contained in an X.509 or OpenPGP certificate */boolhas_private_key(cert_t cert){ struct secret *s; bool has_key = FALSE; struct pubkey *pubkey; pubkey = allocate_RSA_public_key(cert); if(pubkey == NULL) return FALSE; for (s = secrets; s != NULL; s = s->next) { if (s->kind == PPK_RSA && same_RSA_public_key(&s->u.RSA_private_key.pub, &pubkey->u.rsa)) { has_key = TRUE; break; } } free_public_key(pubkey); return has_key;}/* find the appropriate RSA private key (see get_secret). * Failure is indicated by a NULL pointer. */const struct RSA_private_key *get_RSA_private_key(const struct connection *c){ const struct secret *s = get_secret(c, PPK_RSA, TRUE); return s == NULL? NULL : &s->u.RSA_private_key;}/* digest a secrets file * * The file is a sequence of records. A record is a maximal sequence of * tokens such that the first, and only the first, is in the first column * of a line. * * Tokens are generally separated by whitespace and are key words, ids, * strings, or data suitable for ttodata(3). As a nod to convention, * a trailing ":" on what would otherwise be a token is taken as a * separate token. If preceded by whitespace, a "#" is taken as starting * a comment: it and the rest of the line are ignored. * * One kind of record is an include directive. It starts with "include". * The filename is the only other token in the record. * If the filename does not start with /, it is taken to * be relative to the directory containing the current file. * * The other kind of record describes a key. It starts with a * sequence of ids and ends with key information. Each id * is an IP address, a Fully Qualified Domain Name (which will immediately * be resolved), or @FQDN which will be left as a name. * * The key part can be in several forms. * * The old form of the key is still supported: a simple * quoted strings (with no escapes) is taken as a preshred key. * * The new form starts the key part with a ":". * * For Preshared Key, use the "PSK" keyword, and follow it by a string * or a data token suitable for ttodata(3). * * For RSA Private Key, use the "RSA" keyword, followed by a * brace-enclosed list of key field keywords and data values. * The data values are large integers to be decoded by ttodata(3). * The fields are a subset of those used by BIND 8.2 and have the * same names. *//* process rsa key file protected with optional passphrase which can either be * read from ipsec.secrets or prompted for by using whack */err_tprocess_rsa_keyfile(struct RSA_private_key *rsak, int whackfd){ char filename[BUF_LEN]; err_t ugh = NULL; rsa_privkey_t *key = NULL; prompt_pass_t pass; memset(filename,'\0', BUF_LEN); memset(pass.secret,'\0', sizeof(pass.secret)); pass.prompt = FALSE; pass.fd = whackfd; /* we expect the filename of a PKCS#1 private key file */ if (*tok == '"' || *tok == '\'') /* quoted filename */ memcpy(filename, tok+1, flp->cur - tok - 2); else memcpy(filename, tok, flp->cur - tok); if (shift()) { /* we expect an appended passphrase or passphrase prompt*/ if (tokeqword("%prompt")) { if (pass.fd == NULL_FD) return "enter a passphrase using ipsec auto --rereadsecrets"; pass.prompt = TRUE; } else if (*tok == '"' || *tok == '\'') /* quoted passphrase */ memcpy(pass.secret, tok+1, flp->cur - tok - 2); else memcpy(pass.secret, tok, flp->cur - tok); if (shift()) ugh = "RSA private key file -- unexpected token after passphrase"; } key = load_rsa_private_key(filename, &pass); if (key == NULL) ugh = "error loading RSA private key file"; else { mpz_t u; u_int i; for (i = 0; ugh == NULL && i < elemsof(RSA_private_field); i++) { MP_INT *n = (MP_INT *) ((char *)rsak + RSA_private_field[i].offset); if (key->field[i].len > 0) { /* PKCS#1 RSA private key format - complete */ n_to_mpz(n, key->field[i].ptr, key->field[i].len); } else { /* PGP RSA private key format - missing fields */ switch (i) { case 5: /* dP = d mod (p-1) */ mpz_init(u); mpz_sub_ui(u, &rsak->p, 1); mpz_mod(n, &rsak->d, u); mpz_clear(u); break; case 6: /* dQ = d mod (q-1) */ mpz_init(u); mpz_sub_ui(u, &rsak->q, 1); mpz_mod(n, &rsak->d, u); mpz_clear(u); break; case 7: /* qInv = (q^-1) mod p */ mpz_invert(n, &rsak->q, &rsak->p); if (mpz_cmp_ui(n, 0) < 0) mpz_add(n, n, &rsak->p); passert(mpz_cmp(n, &rsak->p) < 0); break; default: break; } } } form_keyid(key->field[1], key->field[0], rsak->pub.keyid, &rsak->pub.k); ugh = RSA_private_key_sanity(rsak); pfree(key->keyobject.ptr); pfree(key); } return ugh;}/* parse PSK from file */static err_tprocess_psk_secret(chunk_t *psk){ err_t ugh = NULL; if (*tok == '"' || *tok == '\'') { clonetochunk(*psk, tok+1, flp->cur - tok - 2, "PSK"); (void) shift(); } else { char buf[RSA_MAX_ENCODING_BYTES]; /* limit on size of binary representation of key */ size_t sz; ugh = ttodatav(tok, flp->cur - tok, 0, buf, sizeof(buf), &sz , diag_space, sizeof(diag_space), TTODATAV_SPACECOUNTS); if (ugh != NULL) { /* ttodata didn't like PSK data */ ugh = builddiag("PSK data malformed (%s): %s", ugh, tok); } else { clonetochunk(*psk, buf, sz, "PSK"); (void) shift(); } } return ugh;}/* Parse fields of RSA private key. * A braced list of keyword and value pairs. * At the moment, each field is required, in order. * The fields come from BIND 8.2's representation */static err_tprocess_rsa_secret(struct RSA_private_key *rsak){ char buf[RSA_MAX_ENCODING_BYTES]; /* limit on size of binary representation of key */ const struct fld *p; /* save bytes of Modulus and PublicExponent for keyid calculation */ unsigned char ebytes[sizeof(buf)]; unsigned char *eb_next = ebytes; chunk_t pub_bytes[2]; chunk_t *pb_next = &pub_bytes[0]; for (p = RSA_private_field; p < &RSA_private_field[elemsof(RSA_private_field)]; p++) { size_t sz; err_t ugh; if (!shift()) { return "premature end of RSA key"; } else if (!tokeqword(p->name)) { return builddiag("%s keyword not found where expected in RSA key" , p->name); } else if (!(shift() && (!tokeq(":") || shift()))) /* ignore optional ":" */ { return "premature end of RSA key"; } else if (NULL != (ugh = ttodatav(tok, flp->cur - tok , 0, buf, sizeof(buf), &sz, diag_space, sizeof(diag_space) , TTODATAV_SPACECOUNTS))) { /* in RSA key, ttodata didn't like */ return builddiag("RSA data malformed (%s): %s", ugh, tok); } else { MP_INT *n = (MP_INT *) ((char *)rsak + p->offset); n_to_mpz(n, buf, sz); if (pb_next < &pub_bytes[elemsof(pub_bytes)]) { if (eb_next - ebytes + sz > sizeof(ebytes)) return "public key takes too many bytes"; setchunk(*pb_next, eb_next, sz); memcpy(eb_next, buf, sz); eb_next += sz; pb_next++; }#if 0 /* debugging info that compromises security */ { 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); loglog(RC_LOG_SERIOUS, "%s: %s", p->name, buf); }#endif } } /* We require an (indented) '}' and the end of the record. * We break down the test so that the diagnostic will be * more helpful. Some people don't seem to wish to indent * the brace! */ if (!shift() || !tokeq("}")) { return "malformed end of RSA private key -- indented '}' required"; } else if (shift()) { return "malformed end of RSA private key -- unexpected token after '}'"; } else { unsigned bits = mpz_sizeinbase(&rsak->pub.n, 2); rsak->pub.k = (bits + BITS_PER_BYTE - 1) / BITS_PER_BYTE; rsak->pub.keyid[0] = '\0'; /* in case of splitkeytoid failure */ splitkeytoid(pub_bytes[1].ptr, pub_bytes[1].len , pub_bytes[0].ptr, pub_bytes[0].len , rsak->pub.keyid, sizeof(rsak->pub.keyid)); return RSA_private_key_sanity(rsak); }}/* * get the matching RSA private key belonging to a given X.509 certificate */const struct RSA_private_key*get_x509_private_key(x509cert_t *cert){ struct secret *s; const struct RSA_private_key *pri = NULL; cert_t c; struct pubkey *pubkey; c.forced = FALSE; c.type = CERT_X509_SIGNATURE; c.u.x509 = cert; pubkey = allocate_RSA_public_key(c); if(pubkey == NULL) return NULL; for (s = secrets; s != NULL; s = s->next) { if (s->kind == PPK_RSA && same_RSA_public_key(&s->u.RSA_private_key.pub, &pubkey->u.rsa)) { pri = &s->u.RSA_private_key; break; } } free_public_key(pubkey); return pri;}#ifdef SMARTCARD/* * process pin read from ipsec.secrets or prompted for it using whack */static err_tprocess_pin(struct secret *s, int whackfd){ smartcard_t *sc; const char *pin_status = "no"; s->kind = PPK_PIN; /* looking for the smartcard keyword */ if (!shift() || strncmp(tok, SCX_TOKEN, strlen(SCX_TOKEN)) != 0) return "PIN keyword must be followed by %smartcard<reader>:<id>"; sc = scx_add(scx_parse_reader_id(tok + strlen(SCX_TOKEN))); s->u.smartcard = sc; scx_share(sc); scx_free_pin(&sc->pin); sc->valid = FALSE; if (!shift()) return "PIN statement must be terminated either by <pin code> or %prompt"; if (tokeqword("%prompt")) { shift(); /* if whackfd exists, whack will be used to prompt for a pin */ if (whackfd != NULL_FD) pin_status = scx_get_pin(sc, whackfd) ? "valid" : "invalid"; } else { /* we read the pin directly from ipsec.secrets */ err_t ugh = process_psk_secret(&sc->pin); if (ugh != NULL) return ugh; /* verify the pin */ pin_status = scx_verify_pin(sc) ? "valid" : "invalid"; }#ifdef SMARTCARD openswan_log(" %s PIN for reader: %d, id: %s", pin_status, sc->reader, sc->id);#else openswan_log(" warning: SMARTCARD support is deactivated in pluto/Makefile!");#endif return NULL;}#endifstatic voidprocess_secret(struct secret *s, int whackfd){ err_t ugh = NULL; whackfd = whackfd; /* shut up compiler */ s->kind = PPK_PSK; /* default */ if (*tok == '"' || *tok == '\'') { /* old PSK format: just a string */ ugh = process_psk_secret(&s->u.preshared_secret); } else if (tokeqword("psk")) { /* preshared key: quoted string or ttodata format */ ugh = !shift()? "unexpected end of record in PSK" : process_psk_secret(&s->u.preshared_secret); } else if (tokeqword("rsa")) { /* RSA key: the fun begins. * A braced list of keyword and value pairs. */ s->kind = PPK_RSA; if (!shift()) { ugh = "bad RSA key syntax"; } else if (tokeq("{")) { ugh = process_rsa_secret(&s->u.RSA_private_key); } else { ugh = process_rsa_keyfile(&s->u.RSA_private_key, whackfd); } DBG(DBG_CONTROL, DBG_log("loaded private key for keyid: %s:%s", enum_name(&ppk_names, s->kind), s->u.RSA_private_key.pub.keyid)); } else if (tokeqword("pin")) {#ifdef SMARTCARD ugh = process_pin(s, whackfd);#else ugh = "Smartcard not supported";#endif } else { ugh = builddiag("unrecognized key format: %s", tok); } if (ugh != NULL) { loglog(RC_LOG_SERIOUS, "\"%s\" line %d: %s" , flp->filename, flp->lino, ugh); pfree(s); } else if (flushline("expected record boundary in key")) { /* gauntlet has been run: install new secret */ lock_certs_and_keys("process_secret"); s->next = secrets; secrets = s; unlock_certs_and_keys("process_secrets"); }}static void process_secrets_file(const char *file_pat, int whackfd); /* forward declaration */static voidprocess_secret_records(int whackfd){ /* read records from ipsec.secrets and load them into our table */ for (;;) { (void)flushline(NULL); /* silently ditch leftovers, if any */ if (flp->bdry == B_file) break; flp->bdry = B_none; /* eat the Record Boundary */ (void)shift(); /* get real first token */ if (tokeqword("include")) { /* an include directive */ char fn[MAX_TOK_LEN]; /* space for filename (I hope) */ char *p = fn; char *end_prefix = strrchr(flp->filename, '/'); if (!shift()) { loglog(RC_LOG_SERIOUS, "\"%s\" line %d: unexpected end of include directive" , flp->filename, flp->lino); continue; /* abandon this record */ } /* if path is relative and including file's pathname has * a non-empty dirname, prefix this path with that dirname. */ if (tok[0] != '/' && end_prefix != NULL) { size_t pl = end_prefix - flp->filename + 1; /* "clamp" length to prevent problems now; * will be rediscovered and reported later. */ if (pl > sizeof(fn)) pl = sizeof(fn);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -