pluto and scepclient use private and public key plugins of libstrongswan

This commit is contained in:
Andreas Steffen
2009-06-09 11:03:32 +02:00
committed by Martin Willi
parent b00fbdb55a
commit 8b799d55ce
46 changed files with 1803 additions and 2597 deletions
+1 -2
View File
@@ -38,8 +38,7 @@ nat_traversal.c nat_traversal.h \
ocsp.c ocsp.h \
packet.c packet.h \
pem.c pem.h \
pgp.c pgp.h \
pkcs1.c pkcs1.h \
pgpcert.c pgpcert.h \
pkcs7.c pkcs7.h \
plutomain.c \
rcv_whack.c rcv_whack.h \
+2 -2
View File
@@ -783,8 +783,8 @@ bool verify_x509acert(x509acert_t *ac, bool strict)
DBG_log("issuer aacert found")
)
if (!check_signature(ac->certificateInfo, ac->signature
, ac->algorithm, ac->algorithm, aacert))
if (!x509_check_signature(ac->certificateInfo, ac->signature, ac->algorithm,
aacert))
{
plog("attribute certificate signature is invalid");
return FALSE;
+2 -2
View File
@@ -385,8 +385,8 @@ trust_authcert_candidate(const x509cert_t *cert, const x509cert_t *alt_chain)
}
}
if (!check_signature(cert->tbsCertificate, cert->signature
, cert->algorithm, cert->algorithm, authcert))
if (!x509_check_signature(cert->tbsCertificate, cert->signature,
cert->algorithm, authcert))
{
plog("certificate signature is invalid");
unlock_authcert_list("trust_authcert_candidate");
+20 -16
View File
@@ -1,5 +1,7 @@
/* Certificate support for IKE authentication
* Copyright (C) 2002-2004 Andreas Steffen, Zuercher Hochschule Winterthur
* Copyright (C) 2002-2009 Andreas Steffen
*
* HSR - Hochschule fuer Technik Rapperswil
*
* 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
@@ -18,17 +20,15 @@
#include <freeswan.h>
#include "library.h"
#include "asn1/asn1.h"
#include "constants.h"
#include "defs.h"
#include "log.h"
#include "id.h"
#include "x509.h"
#include "pgp.h"
#include "pem.h"
#include "certs.h"
#include "pkcs1.h"
/**
* used for initializatin of certs
@@ -118,14 +118,14 @@ bool load_coded_file(char *filename, prompt_pass_t *pass, const char *type,
}
/**
* Loads a PKCS#1 or PGP private RSA key file
* Loads a PKCS#1 or PGP privatekey file
*/
err_t load_rsa_private_key(char* filename, prompt_pass_t *pass,
RSA_private_key_t *key)
private_key_t* load_private_key(char* filename, prompt_pass_t *pass,
key_type_t type)
{
err_t ugh = NULL;
bool pgp = FALSE;
private_key_t *key = NULL;
chunk_t blob = chunk_empty;
bool pgp = FALSE;
char *path = concatenate_paths(PRIVATE_KEY_PATH, filename);
@@ -133,20 +133,24 @@ err_t load_rsa_private_key(char* filename, prompt_pass_t *pass,
{
if (pgp)
{
if (!parse_pgp(blob, NULL, key))
ugh = "syntax error in PGP private key file";
parse_pgp(blob, NULL, &key);
}
else
{
if (!pkcs1_parse_private_key(blob, key))
ugh = "syntax error in PKCS#1 private key file";
key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type,
BUILD_BLOB_ASN1_DER, blob, BUILD_END);
}
if (key == NULL)
{
plog("syntax error in %s private key file", pgp ? "PGP":"PKCS#");
}
free(blob.ptr);
}
else
ugh = "error loading RSA private key file";
return ugh;
{
plog("error loading RSA private key file");
}
return key;
}
/**
+10 -7
View File
@@ -1,5 +1,7 @@
/* Certificate support for IKE authentication
* Copyright (C) 2002-2004 Andreas Steffen, Zuercher Hochschule Winterthur
* Copyright (C) 2002-2009 Andreas Steffen
*
* HSR - Hochschule fuer Technik Rapperswil
*
* 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
@@ -15,9 +17,10 @@
#ifndef _CERTS_H
#define _CERTS_H
#include "pkcs1.h"
#include <credentials/keys/private_key.h>
#include "x509.h"
#include "pgp.h"
#include "pgpcert.h"
/* path definitions for private keys, end certs,
* cacerts, attribute certs and crls
@@ -59,11 +62,11 @@ extern const cert_t empty_cert;
*/
extern bool no_cr_send;
extern err_t load_rsa_private_key(char* filename, prompt_pass_t *pass
, RSA_private_key_t *key);
extern private_key_t* load_private_key(char* filename, prompt_pass_t *pass,
key_type_t type);
extern chunk_t get_mycert(cert_t cert);
extern bool load_coded_file(char *filename, prompt_pass_t *pass
, const char *type, chunk_t *blob, bool *pgp);
extern bool load_coded_file(char *filename, prompt_pass_t *pass,
const char *type, chunk_t *blob, bool *pgp);
extern bool load_cert(char *filename, const char *label, cert_t *cert);
extern bool load_host_cert(char *filename, cert_t *cert);
extern bool load_ca_cert(char *filename, cert_t *cert);
+29 -25
View File
@@ -29,13 +29,15 @@
#include <freeswan.h>
#include "kameipsec.h"
#include <credentials/keys/private_key.h>
#include "constants.h"
#include "defs.h"
#include "id.h"
#include "x509.h"
#include "ca.h"
#include "crl.h"
#include "pgp.h"
#include "pgpcert.h"
#include "certs.h"
#include "ac.h"
#include "smartcard.h"
@@ -2155,17 +2157,16 @@ check_key_recs(enum myid_state try_state
* If so, treat as a kind of failure.
*/
enum myid_state old_myid_state = myid_state;
const struct RSA_private_key *our_RSA_pri;
private_key_t *private;
err_t ugh = NULL;
myid_state = try_state;
if (old_myid_state != myid_state
&& old_myid_state == MYID_SPECIFIED)
if (old_myid_state != myid_state && old_myid_state == MYID_SPECIFIED)
{
ugh = "%myid was specified while we were guessing";
}
else if ((our_RSA_pri = get_RSA_private_key(c)) == NULL)
else if ((private = get_private_key(c)) == NULL)
{
ugh = "we don't know our own RSA key";
}
@@ -2185,7 +2186,7 @@ check_key_recs(enum myid_state try_state
{
ugh = "all our KEY RRs have the wrong public key";
if (kr->key->alg == PUBKEY_ALG_RSA
&& same_RSA_public_key(&our_RSA_pri->pub, &kr->key->u.rsa))
&& private->belongs_to(private, &kr->key->public_key))
{
ugh = NULL; /* good! */
break;
@@ -2198,10 +2199,9 @@ check_key_recs(enum myid_state try_state
}
#endif /* USE_KEYRR */
static err_t
check_txt_recs(enum myid_state try_state
, const struct connection *c
, struct adns_continuation *ac)
static err_t check_txt_recs(enum myid_state try_state,
const struct connection *c,
struct adns_continuation *ac)
{
/* Check if TXT lookup yielded good results.
* Looking up based on our ID. Used if
@@ -2211,7 +2211,7 @@ check_txt_recs(enum myid_state try_state
* If so, treat as a kind of failure.
*/
enum myid_state old_myid_state = myid_state;
const struct RSA_private_key *our_RSA_pri;
private_key_t *private;
err_t ugh = NULL;
myid_state = try_state;
@@ -2221,7 +2221,7 @@ check_txt_recs(enum myid_state try_state
{
ugh = "%myid was specified while we were guessing";
}
else if ((our_RSA_pri = get_RSA_private_key(c)) == NULL)
else if ((private = get_private_key(c)) == NULL)
{
ugh = "we don't know our own RSA key";
}
@@ -2239,9 +2239,11 @@ check_txt_recs(enum myid_state try_state
ugh = "no TXT RR found for us";
for (gwp = ac->gateways_from_dns; gwp != NULL; gwp = gwp->next)
{
public_key_t *pub_key = gwp->key->public_key;
ugh = "all our TXT RRs have the wrong public key";
if (gwp->key->alg == PUBKEY_ALG_RSA
&& same_RSA_public_key(&our_RSA_pri->pub, &gwp->key->u.rsa))
if (pub_key->get_type(pub_key) == KEY_RSA &&
private->belongs_to(private, pub_key))
{
ugh = NULL; /* good! */
break;
@@ -2249,7 +2251,9 @@ check_txt_recs(enum myid_state try_state
}
}
if (ugh != NULL)
{
myid_state = old_myid_state;
}
return ugh;
}
@@ -2513,13 +2517,13 @@ initiate_opportunistic_body(struct find_oppo_bundle *b
* a chance that we did the wrong query.
* If so, treat as a kind of failure.
*/
const struct RSA_private_key *our_RSA_pri = get_RSA_private_key(c);
private_key_t *private = get_private_key(c);
next_step = fos_his_client; /* normal situation */
passert(sr != NULL);
if (our_RSA_pri == NULL)
if (private == NULL)
{
ugh = "we don't know our own RSA key";
}
@@ -2560,7 +2564,7 @@ initiate_opportunistic_body(struct find_oppo_bundle *b
ugh = NULL; /* good! */
break;
}
if (same_RSA_public_key(&our_RSA_pri->pub, &gwp->key->u.rsa))
if (private->belongs_to(private, gwp->key->public_key))
{
ugh = NULL; /* good! */
break;
@@ -2579,11 +2583,11 @@ initiate_opportunistic_body(struct find_oppo_bundle *b
* a chance that we did the wrong query.
* If so, treat as a kind of failure.
*/
const struct RSA_private_key *our_RSA_pri = get_RSA_private_key(c);
private_key_t *private = get_private_key(c);
next_step = fos_his_client; /* unless we decide to look for KEY RR */
if (our_RSA_pri == NULL)
if (private == NULL)
{
ugh = "we don't know our own RSA key";
}
@@ -2604,8 +2608,8 @@ initiate_opportunistic_body(struct find_oppo_bundle *b
passert(same_id(&gwp->gw_id, &sr->this.id));
ugh = "TXT RR for us has wrong key";
if (gwp->gw_key_present
&& same_RSA_public_key(&our_RSA_pri->pub, &gwp->key->u.rsa))
if (gwp->gw_key_present &&
private->belongs_to(private, gwp->key->public_key))
{
DBG(DBG_CONTROL,
DBG_log("initiate on demand found TXT with right public key at: %s"
@@ -2639,11 +2643,11 @@ initiate_opportunistic_body(struct find_oppo_bundle *b
* a chance that we did the wrong query.
* If so, treat as a kind of failure.
*/
const struct RSA_private_key *our_RSA_pri = get_RSA_private_key(c);
private_key_t *private = get_private_key(c);
next_step = fos_his_client; /* always */
if (our_RSA_pri == NULL)
if (private == NULL)
{
ugh = "we don't know our own RSA key";
}
@@ -2663,7 +2667,7 @@ initiate_opportunistic_body(struct find_oppo_bundle *b
{
ugh = "all our KEY RRs have the wrong public key (and no good TXT RR)";
if (kr->key->alg == PUBKEY_ALG_RSA
&& same_RSA_public_key(&our_RSA_pri->pub, &kr->key->u.rsa))
&& private->belongs_to(private, kr->key->public_key))
{
/* do this only once a day */
if (!logged_txt_warning)
@@ -3399,7 +3403,7 @@ refine_host_connection(const struct state *st, const struct id *peer_id
* We must at least be able to find our private key
.*/
if (d->spd.this.sc == NULL /* no smartcard */
&& get_RSA_private_key(d) == NULL) /* no private key */
&& get_private_key(d) == NULL) /* no private key */
continue;
break;
+4 -4
View File
@@ -238,8 +238,8 @@ bool insert_crl(chunk_t blob, chunk_t crl_uri, bool cache_crl)
)
/* check the issuer's signature of the crl */
valid_sig = check_signature(crl->tbsCertList, crl->signature
, crl->algorithm, crl->algorithm, issuer_cert);
valid_sig = x509_check_signature(crl->tbsCertList, crl->signature,
crl->algorithm, issuer_cert);
unlock_authcert_list("insert_crl");
if (!valid_sig)
@@ -656,8 +656,8 @@ verify_by_crl(const x509cert_t *cert, time_t *until, time_t *revocationDate
issuer_cert = get_authcert(crl->issuer, crl->authKeySerialNumber
, crl->authKeyID, AUTH_CA);
valid = check_signature(crl->tbsCertList, crl->signature
, crl->algorithm, crl->algorithm, issuer_cert);
valid = x509_check_signature(crl->tbsCertList, crl->signature,
crl->algorithm, issuer_cert);
unlock_authcert_list("verify_by_crl");
+74 -31
View File
@@ -29,6 +29,9 @@
#include <freeswan.h>
#include <utils/identification.h>
#include <credentials/keys/public_key.h>
#include "constants.h"
#include "adns.h" /* needs <resolv.h> */
#include "defs.h"
@@ -83,7 +86,9 @@ init_adns(void)
{
strcpy(adns_path_space, helper_bin_dir);
if (n > 0 && adns_path_space[n -1] != '/')
{
adns_path_space[n++] = '/';
}
}
}
else
@@ -95,25 +100,33 @@ init_adns(void)
n = readlink("/proc/self/exe", adns_path_space, sizeof(adns_path_space));
if (n < 0)
{
exit_log_errno((e
, "readlink(\"/proc/self/exe\") failed in init_adns()"));
}
}
if ((size_t)n > sizeof(adns_path_space) - sizeof(adns_name))
{
exit_log("path to %s is too long", adns_name);
}
while (n > 0 && adns_path_space[n - 1] != '/')
{
n--;
}
strcpy(adns_path_space + n, adns_name);
adns_path = adns_path_space;
}
if (access(adns_path, X_OK) < 0)
{
exit_log_errno((e, "%s missing or not executable", adns_path));
}
if (pipe(qfds) != 0 || pipe(afds) != 0)
{
exit_log_errno((e, "pipe(2) failed in init_adns()"));
}
adns_pid = fork();
switch (adns_pid)
@@ -128,7 +141,9 @@ init_adns(void)
* Take care to handle case where pipes already use these fds.
*/
if (afds[1] == 0)
{
afds[1] = dup(afds[1]); /* avoid being overwritten */
}
if (qfds[0] != 0)
{
dup2(qfds[0], 0);
@@ -140,16 +155,18 @@ init_adns(void)
close(qfds[1]);
}
if (afds[0] > 1)
{
close(afds[0]);
}
if (afds[1] > 1)
{
close(afds[1]);
}
DBG(DBG_DNS, execlp(adns_path, adns_name, "-d", NULL));
execlp(adns_path, adns_name, NULL);
exit_log_errno((e, "execlp of %s failed", adns_path));
}
default:
/* parent */
close(qfds[0]);
@@ -183,8 +200,10 @@ stop_adns(void)
else if (WIFEXITED(status))
{
if (WEXITSTATUS(status) != 0)
{
plog("ADNS process exited with status %d"
, (int) WEXITSTATUS(status));
}
}
else if (WIFSIGNALED(status))
{
@@ -227,8 +246,9 @@ decode_iii(u_char **pp, struct id *gw_id)
u_char under = *e;
if (p == e)
{
return "TXT " our_TXT_attr_string " badly formed (no gateway specified)";
}
*e = '\0';
if (*p == '@')
{
@@ -236,8 +256,10 @@ decode_iii(u_char **pp, struct id *gw_id)
err_t ugh = atoid(p, gw_id, FALSE);
if (ugh != NULL)
{
return builddiag("malformed FQDN in TXT " our_TXT_attr_string ": %s"
, ugh);
}
}
else
{
@@ -248,12 +270,14 @@ decode_iii(u_char **pp, struct id *gw_id)
, &ip);
if (ugh != NULL)
{
return builddiag("malformed IP address in TXT " our_TXT_attr_string ": %s"
, ugh);
}
if (isanyaddr(&ip))
{
return "gateway address must not be 0.0.0.0 or 0::0";
}
iptoid(&ip, gw_id);
}
@@ -278,14 +302,18 @@ process_txt_rr_body(u_char *str
/* is this for us? */
if (strncasecmp(p, our_TXT_attr, sizeof(our_TXT_attr)-1) != 0)
{
return NULL; /* neither interesting nor bad */
}
p += sizeof(our_TXT_attr) - 1; /* ignore our attribute name */
p += strspn(p, " \t"); /* ignore leading whitespace */
/* decode '(' nnn ')' */
if (*p != '(')
{
return "X-IPsec-Server missing '('";
}
{
char *e;
@@ -293,25 +321,30 @@ process_txt_rr_body(u_char *str
p++;
pref = strtoul(p, &e, 0);
if ((u_char *)e == p)
{
return "malformed X-IPsec-Server priority";
}
p = e + strspn(e, " \t");
if (*p != ')')
{
return "X-IPsec-Server priority missing ')'";
}
p++;
p += strspn(p, " \t");
if (pref > 0xFFFF)
{
return "X-IPsec-Server priority larger than 0xFFFF";
}
}
/* time for '=' */
if (*p != '=')
{
return "X-IPsec-Server priority missing '='";
}
p++;
p += strspn(p, " \t");
@@ -384,29 +417,34 @@ process_txt_rr_body(u_char *str
/* Decode base 64 encoding of key.
* Similar code is in process_lwdnsq_key.
*/
u_char kb[RSA_MAX_ENCODING_BYTES]; /* plenty of space for binary form of public key */
chunk_t kbc;
struct RSA_public_key r;
u_char buf[RSA_MAX_ENCODING_BYTES]; /* plenty of space for binary form of public key */
size_t sz;
err_t ugh;
chunk_t rfc3110_chunk;
public_key_t *key;
err_t ugh = ttodatav(p, 0, 64, kb, sizeof(kb), &kbc.len
, diag_space, sizeof(diag_space), TTODATAV_SPACECOUNTS);
if (ugh != NULL)
ugh = ttodatav(p, 0, 64, buf, sizeof(buf), &sz,
diag_space, sizeof(diag_space), TTODATAV_SPACECOUNTS);
if (ugh)
{
return builddiag("malformed key data: %s", ugh);
if (kbc.len > sizeof(kb))
return builddiag("key data larger than %lu bytes"
, (unsigned long) sizeof(kb));
kbc.ptr = kb;
ugh = unpack_RSA_public_key(&r, &kbc);
if (ugh != NULL)
return builddiag("invalid key data: %s", ugh);
}
if (sz > sizeof(buf))
{
return builddiag("key data larger than %lu bytes",
(unsigned long) sizeof(buf));
}
rfc3110_chunk = chunk_create(buf, sz);
key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA,
BUILD_BLOB_RFC_3110, rfc3110_chunk,
BUILD_END);
if (key == NULL)
{
return builddiag("invalid key data");
}
/* now find a key entry to put it in */
gi.key = public_key_from_rsa(&r);
free_RSA_public_content(&r);
gi.key = public_key_from_rsa(key);
unreference_key(&cr->last_info);
cr->last_info = reference_key(gi.key);
@@ -426,13 +464,18 @@ process_txt_rr_body(u_char *str
{
char cidb[BUF_LEN];
char gwidb[BUF_LEN];
identification_t *keyid;
public_key_t *pub_key;
idtoa(client_id, cidb, sizeof(cidb));
idtoa(&gi.gw_id, gwidb, sizeof(gwidb));
pub_key = gi.key->public_key;
keyid = pub_key->get_id(pub_key, ID_PUBKEY_SHA1);
if (gi.gw_key_present)
{
DBG_log("gateway for %s is %s with key %s"
, cidb, gwidb, gi.key->u.rsa.keyid);
DBG_log("gateway for %s is %s with key %Y"
, cidb, gwidb, keyid);
}
else
{
+109 -255
View File
@@ -34,6 +34,8 @@
#include <crypto/hashers/hasher.h>
#include <crypto/prfs/prf.h>
#include <crypto/rngs/rng.h>
#include <credentials/keys/private_key.h>
#include <credentials/keys/public_key.h>
#include "constants.h"
#include "defs.h"
@@ -1402,35 +1404,44 @@ static bool generate_skeyids_iv(struct state *st)
return prf_block_size;
}
/* Create an RSA signature of a hash.
/* Create a public key signature of a hash.
* Poorly specified in draft-ietf-ipsec-ike-01.txt 6.1.1.2.
* Use PKCS#1 version 1.5 encryption of hash (called
* RSAES-PKCS1-V1_5) in PKCS#2.
*/
static size_t RSA_sign_hash(struct connection *c, u_char sig_val[RSA_MAX_OCTETS],
const u_char *hash_val, size_t hash_len)
static size_t sign_hash(struct connection *c, u_char sig_val[RSA_MAX_OCTETS],
u_char *hash_val, size_t hash_len)
{
size_t sz = 0;
smartcard_t *sc = c->spd.this.sc;
if (sc == NULL) /* no smartcard */
{
const struct RSA_private_key *k = get_RSA_private_key(c);
chunk_t hash, sig;
private_key_t *private = get_private_key(c);
if (k == NULL)
if (private == NULL)
{
return 0; /* failure: no key to use */
sz = k->pub.k;
}
sz = private->get_keysize(private);
passert(RSA_MIN_OCTETS <= sz && 4 + hash_len < sz && sz <= RSA_MAX_OCTETS);
sign_hash(k, hash_val, hash_len, sig_val, sz);
hash = chunk_create(hash_val, hash_len);
sig = chunk_create(sig_val, sz);
if (!private->sign(private, SIGN_RSA_EMSA_PKCS1_NULL, hash, &sig))
{
return 0;
}
memcpy(sig_val, sig.ptr, sz);
free(sig.ptr);
}
else if (sc->valid) /* if valid pin then sign hash on the smartcard */
{
lock_certs_and_keys("RSA_sign_hash");
lock_certs_and_keys("sign_hash");
if (!scx_establish_context(sc) || !scx_login(sc))
{
scx_release_context(sc);
unlock_certs_and_keys("RSA_sign_hash");
unlock_certs_and_keys("sign_hash");
return 0;
}
@@ -1439,7 +1450,7 @@ static size_t RSA_sign_hash(struct connection *c, u_char sig_val[RSA_MAX_OCTETS]
{
plog("failed to get keylength from smartcard");
scx_release_context(sc);
unlock_certs_and_keys("RSA_sign_hash");
unlock_certs_and_keys("sign_hash");
return 0;
}
@@ -1450,142 +1461,11 @@ static size_t RSA_sign_hash(struct connection *c, u_char sig_val[RSA_MAX_OCTETS]
sz = scx_sign_hash(sc, hash_val, hash_len, sig_val, sz) ? sz : 0;
if (!pkcs11_keep_state)
scx_release_context(sc);
unlock_certs_and_keys("RSA_sign_hash");
unlock_certs_and_keys("sign_hash");
}
return sz;
}
/* Check a Main Mode RSA Signature against computed hash using RSA public key k.
*
* As a side effect, on success, the public key is copied into the
* state object to record the authenticator.
*
* Can fail because wrong public key is used or because hash disagrees.
* We distinguish because diagnostics should also.
*
* The result is NULL if the Signature checked out.
* Otherwise, the first character of the result indicates
* how far along failure occurred. A greater character signifies
* greater progress.
*
* Classes:
* 0 reserved for caller
* 1 SIG length doesn't match key length -- wrong key
* 2-8 malformed ECB after decryption -- probably wrong key
* 9 decrypted hash != computed hash -- probably correct key
*
* Although the math should be the same for generating and checking signatures,
* it is not: the knowledge of the private key allows more efficient (i.e.
* different) computation for encryption.
*/
static err_t try_RSA_signature(const u_char hash_val[MAX_DIGEST_LEN],
size_t hash_len, const pb_stream *sig_pbs,
pubkey_t *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 *hash_in_s = &s[sig_len - hash_len];
const struct RSA_public_key *k = &kr->u.rsa;
/* decrypt the signature -- reversing RSA_sign_hash */
if (sig_len != k->k)
{
/* XXX notification: INVALID_KEY_INFORMATION */
return "1" "SIG length does not match public key length";
}
/* 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);
free(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.
@@ -1597,54 +1477,39 @@ static err_t try_RSA_signature(const u_char hash_val[MAX_DIGEST_LEN],
* 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 */
chunk_t hash;
chunk_t sig;
int tried_cnt; /* number of keys tried */
char tried[50]; /* keyids of tried public keys */
char *tn; /* roof of tried[] */
};
static bool take_a_crack(struct tac_state *s, pubkey_t *kr,
const char *story USED_BY_DEBUG)
static bool take_a_crack(struct tac_state *s, pubkey_t *kr)
{
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;
public_key_t *pub_key = kr->public_key;
identification_t *keyid = pub_key->get_id(pub_key, ID_PUBKEY_SHA1);
s->tried_cnt++;
if (ugh == NULL)
if (pub_key->verify(pub_key, SIGN_RSA_EMSA_PKCS1_NULL, s->hash, s->sig))
{
DBG(DBG_CRYPT | DBG_CONTROL
, DBG_log("an RSA Sig check passed with *%s [%s]"
, k->keyid, story));
DBG(DBG_CRYPT | DBG_CONTROL,
DBG_log("signature check passed with keyid %Y", keyid)
)
unreference_key(&s->st->st_peer_pubkey);
s->st->st_peer_pubkey = reference_key(kr);
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);
}
DBG(DBG_CRYPT,
DBG_log("signature check failed with keyid %Y", keyid)
)
return FALSE;
}
}
static stf_status RSA_check_signature(const struct id* peer, struct state *st,
const u_char hash_val[MAX_DIGEST_LEN],
u_char hash_val[MAX_DIGEST_LEN],
size_t hash_len, const pb_stream *sig_pbs,
#ifdef USE_KEYRR
const pubkey_list_t *keys_from_dns,
@@ -1653,16 +1518,11 @@ static stf_status RSA_check_signature(const struct id* peer, struct state *st,
{
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.hash = chunk_create(hash_val, hash_len);
s.sig = chunk_create(sig_pbs->cur, pbs_left(sig_pbs));
s.tried_cnt = 0;
s.tn = s.tried;
/* try all gateway records hung off c */
if (c->policy & POLICY_OPPO)
@@ -1672,10 +1532,11 @@ static stf_status RSA_check_signature(const struct id* peer, struct state *st,
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"))
if (gw->gw_key_present && same_id(&gw->gw_id, &c->spd.that.id)&&
take_a_crack(&s, gw->key))
{
return STF_OK;
}
}
}
@@ -1688,8 +1549,9 @@ static stf_status RSA_check_signature(const struct id* peer, struct state *st,
for (p = pubkeys; p != NULL; p = *pp)
{
pubkey_t *key = p->key;
key_type_t type = key->public_key->get_type(key->public_key);
if (key->alg == PUBKEY_ALG_RSA && same_id(peer, &key->id))
if (type == KEY_RSA && same_id(peer, &key->id))
{
time_t now = time(NULL);
@@ -1702,18 +1564,19 @@ static stf_status RSA_check_signature(const struct id* peer, struct state *st,
continue; /* continue with next public key */
}
if (take_a_crack(&s, key, "preloaded key"))
return STF_OK;
if (take_a_crack(&s, 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 no key was found 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 (s.tried_cnt == 0 && c->spd.that.key_from_DNS_on_demand)
{
if (gateways_from_dns != NULL)
{
@@ -1721,9 +1584,12 @@ static stf_status RSA_check_signature(const struct id* peer, struct state *st,
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"))
{
if (gwp->gw_key_present && take_a_crack(&s, gwp->key))
{
return STF_OK;
}
}
}
#ifdef USE_KEYRR
else if (keys_from_dns != NULL)
@@ -1732,9 +1598,12 @@ static stf_status RSA_check_signature(const struct id* peer, struct state *st,
const pubkey_list_t *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"))
{
if (kr->key->alg == PUBKEY_ALG_RSA && take_a_crack(&s, kr->key))
{
return STF_OK;
}
}
}
#endif /* USE_KEYRR */
else
@@ -1748,53 +1617,32 @@ static stf_status RSA_check_signature(const struct id* peer, struct state *st,
{
char id_buf[BUF_LEN]; /* arbitrary limit on length of ID reported */
(void) idtoa(peer, id_buf, sizeof(id_buf));
idtoa(peer, id_buf, sizeof(id_buf));
if (s.best_ugh == NULL)
if (s.tried_cnt == 0)
{
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;
loglog(RC_LOG_SERIOUS, "no public key known for '%s'", id_buf);
}
if (s.best_ugh[0] == '9')
else if (s.tried_cnt == 1)
{
loglog(RC_LOG_SERIOUS, "%s", s.best_ugh + 1);
/* XXX Could send notification back */
return STF_FAIL + INVALID_HASH_INFORMATION;
loglog(RC_LOG_SERIOUS, "signature check for '%s' failed: "
" wrong key?; tried %d", id_buf, s.tried_cnt);
DBG(DBG_CONTROL,
DBG_log("public key for '%s' failed: "
"decrypted SIG payload into a malformed ECB", id_buf)
)
}
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;
loglog(RC_LOG_SERIOUS, "signature check for '%s' failed: "
"tried %d keys but none worked.", id_buf, s.tried_cnt);
DBG(DBG_CONTROL,
DBG_log("all %d public keys for '%s' failed: "
"best decrypted SIG payload into a malformed ECB",
s.tried_cnt, id_buf)
)
}
return STF_FAIL + INVALID_KEY_INFORMATION;
}
}
@@ -2245,6 +2093,7 @@ static void decode_cert(struct msg_digest *md)
{
plog("X.509 certificate rejected");
}
DESTROY_IF(cert.public_key);
free_generalNames(cert.subjectAltName, FALSE);
free_generalNames(cert.crlDistributionPoints, FALSE);
}
@@ -2749,9 +2598,9 @@ static bool has_preloaded_public_key(struct state *st)
for (p = pubkeys; p != NULL; p = p->next)
{
pubkey_t *key = p->key;
key_type_t type = key->public_key->get_type(key->public_key);
if (key->alg == PUBKEY_ALG_RSA &&
same_id(&c->spd.that.id, &key->id) &&
if (type == KEY_RSA && same_id(&c->spd.that.id, &key->id) &&
key->until_time == UNDEFINED_TIME)
{
/* found a preloaded public key */
@@ -3595,12 +3444,12 @@ stf_status main_inR2_outI3(struct msg_digest *md)
{
/* SIG_I out */
u_char sig_val[RSA_MAX_OCTETS];
size_t sig_len = RSA_sign_hash(st->st_connection
, sig_val, hash_val, hash_len);
size_t sig_len = sign_hash(st->st_connection, sig_val, hash_val,
hash_len);
if (sig_len == 0)
{
loglog(RC_LOG_SERIOUS, "unable to locate my private key for RSA Signature");
loglog(RC_LOG_SERIOUS, "unable to locate my private key for signature");
return STF_FAIL + AUTHENTICATION_FAILED;
}
@@ -3997,12 +3846,12 @@ main_inI3_outR3_tail(struct msg_digest *md
{
/* SIG_R out */
u_char sig_val[RSA_MAX_OCTETS];
size_t sig_len = RSA_sign_hash(st->st_connection
, sig_val, hash_val, hash_len);
size_t sig_len = sign_hash(st->st_connection, sig_val, hash_val,
hash_len);
if (sig_len == 0)
{
loglog(RC_LOG_SERIOUS, "unable to locate my private key for RSA Signature");
loglog(RC_LOG_SERIOUS, "unable to locate my private key for signature");
return STF_FAIL + AUTHENTICATION_FAILED;
}
@@ -4479,10 +4328,10 @@ static enum verify_oppo_step quick_inI1_outR1_process_answer(
case vos_our_client:
next_step = vos_his_client;
{
const struct RSA_private_key *pri = get_RSA_private_key(c);
private_key_t *private = get_private_key(c);
struct gw_info *gwp;
if (pri == NULL)
if (private == NULL)
{
ugh = "we don't know our own key";
break;
@@ -4503,7 +4352,7 @@ static enum verify_oppo_step quick_inI1_outR1_process_answer(
ugh = NULL; /* good! */
break;
}
else if (same_RSA_public_key(&pri->pub, &gwp->key->u.rsa))
else if (private->belongs_to(private, gwp->key->public_key))
{
ugh = NULL; /* good! */
break;
@@ -4515,9 +4364,9 @@ static enum verify_oppo_step quick_inI1_outR1_process_answer(
case vos_our_txt:
next_step = vos_his_client;
{
const struct RSA_private_key *pri = get_RSA_private_key(c);
private_key_t *private = get_private_key(c);
if (pri == NULL)
if (private == NULL)
{
ugh = "we don't know our own key";
break;
@@ -4534,7 +4383,7 @@ static enum verify_oppo_step quick_inI1_outR1_process_answer(
ugh = "our client delegation depends on our " RRNAME " record, but it has the wrong public key";
#endif
if (gwp->gw_key_present
&& same_RSA_public_key(&pri->pub, &gwp->key->u.rsa))
&& private->belongs_to(private, gwp->key->public_key))
{
ugh = NULL; /* good! */
break;
@@ -4551,9 +4400,9 @@ static enum verify_oppo_step quick_inI1_outR1_process_answer(
case vos_our_key:
next_step = vos_his_client;
{
const struct RSA_private_key *pri = get_RSA_private_key(c);
private_key_t *private = get_private_key(c);
if (pri == NULL)
if (private == NULL)
{
ugh = "we don't know our own key";
break;
@@ -4565,7 +4414,7 @@ static enum verify_oppo_step quick_inI1_outR1_process_answer(
for (kp = ac->keys_from_dns; kp != NULL; kp = kp->next)
{
ugh = "our client delegation depends on our " RRNAME " record, but it has the wrong public key";
if (same_RSA_public_key(&pri->pub, &kp->key->u.rsa))
if (private->belongs_to(private, kp->key->public_key))
{
/* do this only once a day */
if (!logged_txt_warning)
@@ -4585,11 +4434,15 @@ static enum verify_oppo_step quick_inI1_outR1_process_answer(
case vos_his_client:
next_step = vos_done;
{
public_key_t *pub_key;
identification_t *p1st_keyid;
struct gw_info *gwp;
/* check that the public key that authenticated
* the ISAKMP SA (p1st) will do for this gateway.
*/
pub_key = p1st->st_peer_pubkey->public_key;
p1st_keyid = pub_key->get_id(pub_key, ID_PUBKEY_INFO_SHA1);
ugh = "peer's client does not delegate to peer";
for (gwp = ac->gateways_from_dns; gwp != NULL; gwp = gwp->next)
@@ -4601,9 +4454,10 @@ static enum verify_oppo_step quick_inI1_outR1_process_answer(
* it implies fetching a KEY from the same
* place we must have gotten it.
*/
if (!gwp->gw_key_present
|| same_RSA_public_key(&p1st->st_peer_pubkey->u.rsa
, &gwp->key->u.rsa))
if (!gwp->gw_key_present || p1st_keyid->equals(p1st_keyid,
gwp->key->public_key->get_id(gwp->key->public_key,
ID_PUBKEY_INFO_SHA1))
)
{
ugh = NULL; /* good! */
break;
+3 -2
View File
@@ -488,10 +488,11 @@ static bool do_command(struct connection *c, struct spd_route *sr,
for (p = pubkeys; p != NULL; p = p->next)
{
pubkey_t *key = p->key;
key_type_t type = key->public_key->get_type(key->public_key);
int pathlen;
if (key->alg == PUBKEY_ALG_RSA && same_id(&sr->that.id, &key->id)
&& trusted_ca(key->issuer, sr->that.ca, &pathlen))
if (type == KEY_RSA && same_id(&sr->that.id, &key->id) &&
trusted_ca(key->issuer, sr->that.ca, &pathlen))
{
dntoa_or_null(peerca_str, BUF_LEN, key->issuer, "");
escape_metachar(peerca_str, secure_peerca_str, sizeof(secure_peerca_str));
+265 -366
View File
File diff suppressed because it is too large Load Diff
+15 -20
View File
@@ -1,5 +1,6 @@
/* mechanisms for preshared keys (public, private, and preshared secrets)
* Copyright (C) 1998-2002 D. Hugh Redelmeier.
* Copyright (C) 2009 Andreas Steffen, Hochschule fuer Technik Rapperswil
*
* 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
@@ -15,9 +16,9 @@
#ifndef _KEYS_H
#define _KEYS_H
#include <gmp.h> /* GNU Multi-Precision library */
#include <credentials/keys/private_key.h>
#include <credentials/keys/public_key.h>
#include "pkcs1.h"
#include "certs.h"
#ifndef SHARED_SECRETS_FILE
@@ -31,8 +32,7 @@ extern void free_preshared_secrets(void);
enum PrivateKeyKind {
PPK_PSK,
/* PPK_DSS, */ /* not implemented */
PPK_RSA,
PPK_PUBKEY,
PPK_XAUTH,
PPK_PIN
};
@@ -43,9 +43,8 @@ extern void xauth_defaults(void);
struct connection;
extern const chunk_t *get_preshared_secret(const struct connection *c);
extern err_t unpack_RSA_public_key(RSA_public_key_t *rsa, const chunk_t *pubkey);
extern const RSA_private_key_t *get_RSA_private_key(const struct connection *c);
extern const RSA_private_key_t *get_x509_private_key(const x509cert_t *cert);
extern private_key_t *get_private_key(const struct connection *c);
extern private_key_t *get_x509_private_key(const x509cert_t *cert);
/* public key machinery */
@@ -62,10 +61,7 @@ struct pubkey {
, until_time;
chunk_t issuer;
chunk_t serial;
enum pubkey_alg alg;
union {
RSA_public_key_t rsa;
} u;
public_key_t *public_key;
};
typedef struct pubkey_list pubkey_list_t;
@@ -77,21 +73,20 @@ struct pubkey_list {
extern pubkey_list_t *pubkeys; /* keys from ipsec.conf or from certs */
extern pubkey_t *public_key_from_rsa(const RSA_public_key_t *k);
extern pubkey_t *public_key_from_rsa(public_key_t *key);
extern pubkey_list_t *free_public_keyentry(pubkey_list_t *p);
extern void free_public_keys(pubkey_list_t **keys);
extern void free_remembered_public_keys(void);
extern void delete_public_keys(const struct id *id, enum pubkey_alg alg
, chunk_t issuer, chunk_t serial);
extern void delete_public_keys(const struct id *id, key_type_t type,
chunk_t issuer, chunk_t serial);
extern pubkey_t *reference_key(pubkey_t *pk);
extern void unreference_key(pubkey_t **pkp);
extern err_t add_public_key(const struct id *id
, enum dns_auth_level dns_auth_level
, enum pubkey_alg alg
, const chunk_t *key
, pubkey_list_t **head);
extern bool add_public_key(const struct id *id,
enum dns_auth_level dns_auth_level,
enum pubkey_alg alg,
chunk_t rfc3110_key,
pubkey_list_t **head);
extern bool has_private_key(cert_t cert);
extern void add_x509_public_key(x509cert_t *cert, time_t until
+76 -70
View File
@@ -39,7 +39,6 @@
#include "certs.h"
#include "smartcard.h"
#include "whack.h"
#include "pkcs1.h"
#include "keys.h"
#include "fetch.h"
#include "ocsp.h"
@@ -159,7 +158,7 @@ static x509cert_t *ocsp_requestor_cert = NULL;
static smartcard_t *ocsp_requestor_sc = NULL;
static const struct RSA_private_key *ocsp_requestor_pri = NULL;
static private_key_t *ocsp_requestor_key = NULL;
/**
* ASN.1 definition of ocspResponse
@@ -293,8 +292,9 @@ static const asn1Object_t singleResponseObjects[] = {
*/
static bool build_ocsp_location(const x509cert_t *cert, ocsp_location_t *location)
{
hasher_t *hasher;
static u_char digest[HASH_SIZE_SHA1]; /* temporary storage */
location->uri = cert->accessLocation;
if (location->uri.ptr == NULL)
@@ -311,8 +311,15 @@ static bool build_ocsp_location(const x509cert_t *cert, ocsp_location_t *locatio
}
}
/* compute authNameID from as SHA-1 hash of issuer DN */
location->authNameID = chunk_create(digest, HASH_SIZE_SHA1);
compute_digest(cert->issuer, OID_SHA1, &location->authNameID);
hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
if (hasher == NULL)
{
return FALSE;
}
hasher->get_hash(hasher, cert->issuer, digest);
hasher->destroy(hasher);
location->next = NULL;
location->issuer = cert->issuer;
@@ -660,7 +667,7 @@ static bool get_ocsp_requestor_cert(ocsp_location_t *location)
/* initialize temporary static storage */
ocsp_requestor_cert = NULL;
ocsp_requestor_sc = NULL;
ocsp_requestor_pri = NULL;
ocsp_requestor_key = NULL;
for (;;)
{
@@ -699,15 +706,15 @@ static bool get_ocsp_requestor_cert(ocsp_location_t *location)
else
{
/* look for a matching private key in the chained list */
const struct RSA_private_key *pri = get_x509_private_key(cert);
private_key_t *private = get_x509_private_key(cert);
if (pri != NULL)
if (private != NULL)
{
DBG(DBG_CONTROL,
DBG_log("matching private key found")
)
ocsp_requestor_cert = cert;
ocsp_requestor_pri = pri;
ocsp_requestor_key = private;
return TRUE;
}
}
@@ -715,50 +722,58 @@ static bool get_ocsp_requestor_cert(ocsp_location_t *location)
return FALSE;
}
static chunk_t generate_signature(chunk_t digest, smartcard_t *sc,
const RSA_private_key_t *pri)
static chunk_t sc_build_sha1_signature(chunk_t tbs, smartcard_t *sc)
{
chunk_t sigdata;
hasher_t *hasher;
u_char *pos;
u_char digest_buf[HASH_SIZE_SHA1];
chunk_t digest = chunk_from_buf(digest_buf);
chunk_t digest_info, sigdata;
size_t siglen = 0;
if (sc != NULL)
if (!scx_establish_context(sc) || !scx_login(sc))
{
/* RSA signature is done on smartcard */
if (!scx_establish_context(sc) || !scx_login(sc))
{
scx_release_context(sc);
return chunk_empty;
}
siglen = scx_get_keylength(sc);
if (siglen == 0)
{
plog("failed to get keylength from smartcard");
scx_release_context(sc);
return chunk_empty;
}
DBG(DBG_CONTROL | DBG_CRYPT,
DBG_log("signing hash with RSA key from smartcard (slot: %d, id: %s)"
, (int)sc->slot, sc->id)
)
pos = asn1_build_object(&sigdata, ASN1_BIT_STRING, 1 + siglen);
*pos++ = 0x00;
scx_sign_hash(sc, digest.ptr, digest.len, pos, siglen);
if (!pkcs11_keep_state)
scx_release_context(sc);
scx_release_context(sc);
return chunk_empty;
}
else
siglen = scx_get_keylength(sc);
if (siglen == 0)
{
/* RSA signature is done in software */
siglen = pri->pub.k;
pos = asn1_build_object(&sigdata, ASN1_BIT_STRING, 1 + siglen);
*pos++ = 0x00;
sign_hash(pri, digest.ptr, digest.len, pos, siglen);
plog("failed to get keylength from smartcard");
scx_release_context(sc);
return chunk_empty;
}
DBG(DBG_CONTROL | DBG_CRYPT,
DBG_log("signing hash with RSA key from smartcard (slot: %d, id: %s)"
, (int)sc->slot, sc->id)
)
hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
if (hasher == NULL)
{
return chunk_empty;
}
hasher->get_hash(hasher, tbs, digest_buf);
hasher->destroy(hasher);
/* according to PKCS#1 v2.1 digest must be packaged into
* an ASN.1 structure for encryption
*/
digest_info = asn1_wrap(ASN1_SEQUENCE, "cm"
, asn1_algorithmIdentifier(OID_SHA1)
, asn1_simple_object(ASN1_OCTET_STRING, digest));
pos = asn1_build_object(&sigdata, ASN1_BIT_STRING, 1 + siglen);
*pos++ = 0x00;
scx_sign_hash(sc, digest_info.ptr, digest_info.len, pos, siglen);
free(digest_info.ptr);
if (!pkcs11_keep_state)
{
scx_release_context(sc);
}
return sigdata;
}
@@ -770,30 +785,22 @@ static chunk_t generate_signature(chunk_t digest, smartcard_t *sc,
static chunk_t build_signature(chunk_t tbsRequest)
{
chunk_t sigdata, certs;
chunk_t digest_info;
u_char digest_buf[MAX_DIGEST_LEN];
chunk_t digest_raw = { digest_buf, MAX_DIGEST_LEN };
if (!compute_digest(tbsRequest, OID_SHA1, &digest_raw))
return chunk_empty;
/* according to PKCS#1 v2.1 digest must be packaged into
* an ASN.1 structure for encryption
*/
digest_info = asn1_wrap(ASN1_SEQUENCE, "cm"
, asn1_algorithmIdentifier(OID_SHA1)
, asn1_simple_object(ASN1_OCTET_STRING, digest_raw));
/* generate the RSA signature */
sigdata = generate_signature(digest_info
, ocsp_requestor_sc
, ocsp_requestor_pri);
free(digest_info.ptr);
/* has the RSA signature generation been successful? */
if (ocsp_requestor_sc != NULL)
{
/* RSA signature is done on smartcard */
sigdata = sc_build_sha1_signature(tbsRequest, ocsp_requestor_sc);
}
else
{
/* RSA signature is done in software */
sigdata = x509_build_signature(tbsRequest, OID_SHA1, ocsp_requestor_key,
TRUE);
}
if (sigdata.ptr == NULL)
{
return chunk_empty;
}
/* include our certificate */
certs = asn1_wrap(ASN1_CONTEXT_C_0, "m"
@@ -992,8 +999,7 @@ static bool valid_ocsp_response(response_t *res)
DBG_log("ocsp signer cert found")
)
if (!check_signature(res->tbs, res->signature, res->algorithm
, res->algorithm, authcert))
if (!x509_check_signature(res->tbs, res->signature, res->algorithm, authcert))
{
plog("signature of ocsp response is invalid");
unlock_authcert_list("valid_ocsp_response");
@@ -1051,8 +1057,8 @@ static bool valid_ocsp_response(response_t *res)
DBG_log("issuer cacert found")
)
if (!check_signature(cert->tbsCertificate, cert->signature
, cert->algorithm, cert->algorithm, authcert))
if (!x509_check_signature(cert->tbsCertificate, cert->signature,
cert->algorithm, authcert))
{
plog("certificate signature is invalid");
unlock_authcert_list("valid_ocsp_response");
+65 -217
View File
@@ -1,5 +1,7 @@
/* Support of OpenPGP certificates
* Copyright (C) 2002-2004 Andreas Steffen, Zuercher Hochschule Winterthur
* Copyright (C) 2002-2009 Andreas Steffen
*
* HSR - Hochschule fuer Technik Rapperswil
*
* 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
@@ -19,6 +21,7 @@
#include <freeswan.h>
#include <library.h>
#include <pgp/pgp.h>
#include <crypto/hashers/hasher.h>
#include "constants.h"
@@ -26,10 +29,9 @@
#include "mp_defs.h"
#include "log.h"
#include "id.h"
#include "pgp.h"
#include "pgpcert.h"
#include "certs.h"
#include "whack.h"
#include "pkcs1.h"
#include "keys.h"
/*
@@ -87,36 +89,6 @@ static const char *const pgp_packet_type_name[] = {
#define PGP_PUBKEY_ALG_ECDSA 19
#define PGP_PUBKEY_ALG_ELGAMAL 20
/*
* OpenPGP symmetric key algorithms defined in section 9.2 of RFC 2440
*/
#define PGP_SYM_ALG_PLAIN 0
#define PGP_SYM_ALG_IDEA 1
#define PGP_SYM_ALG_3DES 2
#define PGP_SYM_ALG_CAST5 3
#define PGP_SYM_ALG_BLOWFISH 4
#define PGP_SYM_ALG_SAFER 5
#define PGP_SYM_ALG_DES 6
#define PGP_SYM_ALG_AES 7
#define PGP_SYM_ALG_AES_192 8
#define PGP_SYM_ALG_AES_256 9
#define PGP_SYM_ALG_TWOFISH 10
#define PGP_SYM_ALG_ROOF 11
static const char *const pgp_sym_alg_name[] = {
"Plaintext",
"IDEA",
"3DES",
"CAST5",
"Blowfish",
"SAFER",
"DES",
"AES",
"AES-192",
"AES-256",
"Twofish"
};
/*
* Size of PGP Key ID
*/
@@ -129,28 +101,15 @@ const pgpcert_t empty_pgpcert = {
{ NULL, 0 }, /* certificate */
0 , /* created */
0 , /* until */
0 , /* pubkeyAlgorithm */
{ NULL, 0 }, /* modulus */
{ NULL, 0 }, /* publicExponent */
"" /* fingerprint */
NULL , /* public key */
NULL /* fingerprint */
};
static size_t
pgp_size(chunk_t *blob, int len)
{
size_t size = 0;
blob->len -= len;
while (len-- > 0)
size = 256*size + *blob->ptr++;
return size;
}
/*
* extracts the length of a PGP packet
*/
static size_t
pgp_old_packet_length(chunk_t *blob)
static size_t pgp_old_packet_length(chunk_t *blob)
{
/* bits 0 and 1 define the packet length type */
int len_type = 0x03 & *blob->ptr++;
@@ -158,14 +117,13 @@ pgp_old_packet_length(chunk_t *blob)
blob->len--;
/* len_type: 0 -> 1 byte, 1 -> 2 bytes, 2 -> 4 bytes */
return pgp_size(blob, (len_type == 0)? 1: len_type << 1);
return pgp_length(blob, (len_type == 0)? 1: len_type << 1);
}
/*
* extracts PGP packet version (V3 or V4)
*/
static u_char
pgp_version(chunk_t *blob)
static u_char pgp_version(chunk_t *blob)
{
u_char version = *blob->ptr++;
blob->len--;
@@ -179,10 +137,10 @@ pgp_version(chunk_t *blob)
/*
* Parse OpenPGP public key packet defined in section 5.5.2 of RFC 2440
*/
static bool
parse_pgp_pubkey_packet(chunk_t *packet, pgpcert_t *cert)
static bool parse_pgp_pubkey_packet(chunk_t *packet, pgpcert_t *cert)
{
u_char version = pgp_version(packet);
public_key_t *key;
if (version < 3 || version > 4)
{
@@ -191,7 +149,7 @@ parse_pgp_pubkey_packet(chunk_t *packet, pgpcert_t *cert)
}
/* creation date - 4 bytes */
cert->created = (time_t)pgp_size(packet, 4);
cert->created = (time_t)pgp_length(packet, 4);
DBG(DBG_PARSING,
DBG_log("L3 - created:");
DBG_log(" %T", &cert->created, TRUE)
@@ -200,12 +158,13 @@ parse_pgp_pubkey_packet(chunk_t *packet, pgpcert_t *cert)
if (version == 3)
{
/* validity in days - 2 bytes */
cert->until = (time_t)pgp_size(packet, 2);
cert->until = (time_t)pgp_length(packet, 2);
/* validity of 0 days means that the key never expires */
if (cert->until > 0)
{
cert->until = cert->created + 24*3600*cert->until;
}
DBG(DBG_PARSING,
DBG_log("L3 - until:");
DBG_log(" %T", &cert->until, TRUE);
@@ -217,49 +176,29 @@ parse_pgp_pubkey_packet(chunk_t *packet, pgpcert_t *cert)
DBG_log("L3 - public key algorithm:")
)
switch (pgp_size(packet, 1))
switch (pgp_length(packet, 1))
{
case PGP_PUBKEY_ALG_RSA:
case PGP_PUBKEY_ALG_RSA_SIGN_ONLY:
cert->pubkeyAlg = PUBKEY_ALG_RSA;
DBG(DBG_PARSING,
DBG_log(" RSA")
)
/* modulus n */
cert->modulus.len = (pgp_size(packet, 2)+7) / BITS_PER_BYTE;
cert->modulus.ptr = packet->ptr;
packet->ptr += cert->modulus.len;
packet->len -= cert->modulus.len;
DBG(DBG_PARSING,
DBG_log("L3 - modulus:")
)
DBG_cond_dump_chunk(DBG_RAW, "", cert->modulus);
/* public exponent e */
cert->publicExponent.len = (pgp_size(packet, 2)+7) / BITS_PER_BYTE;
cert->publicExponent.ptr = packet->ptr;
packet->ptr += cert->publicExponent.len;
packet->len -= cert->publicExponent.len;
DBG(DBG_PARSING,
DBG_log("L3 - public exponent:")
)
DBG_cond_dump_chunk(DBG_RAW, "", cert->publicExponent);
key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_RSA,
BUILD_BLOB_PGP, *packet,
BUILD_END);
if (key == NULL)
{
return FALSE;
}
cert->public_key = key;
if (version == 3)
{
hasher_t *hasher;
/* a V3 fingerprint is the MD5 hash of modulus and public exponent */
hasher = lib->crypto->create_hasher(lib->crypto, HASH_MD5);
if (hasher == NULL)
cert->fingerprint = key->get_id(key, ID_KEY_ID);
if (cert->fingerprint == NULL)
{
plog(" computation of V3 key ID failed, no MD5 hasher is available");
return FALSE;
}
hasher->get_hash(hasher, cert->modulus, NULL);
hasher->get_hash(hasher, cert->publicExponent, cert->fingerprint);
hasher->destroy(hasher);
}
else
{
@@ -267,14 +206,12 @@ parse_pgp_pubkey_packet(chunk_t *packet, pgpcert_t *cert)
}
break;
case PGP_PUBKEY_ALG_DSA:
cert->pubkeyAlg = PUBKEY_ALG_DSA;
DBG(DBG_PARSING,
DBG_log(" DSA")
)
plog(" DSA public keys not supported");
return FALSE;
default:
cert->pubkeyAlg = 0;
DBG(DBG_PARSING,
DBG_log(" other")
)
@@ -284,104 +221,10 @@ parse_pgp_pubkey_packet(chunk_t *packet, pgpcert_t *cert)
return TRUE;
}
/*
* Parse OpenPGP secret key packet defined in section 5.5.3 of RFC 2440
*/
static bool
parse_pgp_secretkey_packet(chunk_t *packet, RSA_private_key_t *key)
{
int i, s2k;
pgpcert_t cert = empty_pgpcert;
if (!parse_pgp_pubkey_packet(packet, &cert))
return FALSE;
init_RSA_public_key((RSA_public_key_t *)key, cert.publicExponent
, cert.modulus);
/* string-to-key usage */
s2k = pgp_size(packet, 1);
DBG(DBG_PARSING,
DBG_log("L3 - string-to-key: %d", s2k)
)
if (s2k == 255)
{
plog(" string-to-key specifiers not supported");
return FALSE;
}
if (s2k >= PGP_SYM_ALG_ROOF)
{
plog(" undefined symmetric key algorithm");
return FALSE;
}
/* a known symmetric key algorithm is specified*/
DBG(DBG_PARSING,
DBG_log(" %s", pgp_sym_alg_name[s2k])
)
/* private key is unencrypted */
if (s2k == PGP_SYM_ALG_PLAIN)
{
for (i = 2; i < RSA_PRIVATE_FIELD_ELEMENTS; i++)
{
mpz_t u; /* auxiliary variable */
/* compute offset to private key component i*/
MP_INT *n = (MP_INT*)((char *)key + RSA_private_field[i].offset);
switch (i)
{
case 2:
case 3:
case 4:
{
size_t len = (pgp_size(packet, 2)+7) / BITS_PER_BYTE;
n_to_mpz(n, packet->ptr, len);
DBG(DBG_PARSING,
DBG_log("L3 - %s:", RSA_private_field[i].name)
)
DBG_cond_dump(DBG_PRIVATE, "", packet->ptr, len);
packet->ptr += len;
packet->len -= len;
}
break;
case 5: /* dP = d mod (p-1) */
mpz_init(u);
mpz_sub_ui(u, &key->p, 1);
mpz_mod(n, &key->d, u);
mpz_clear(u);
break;
case 6: /* dQ = d mod (q-1) */
mpz_init(u);
mpz_sub_ui(u, &key->q, 1);
mpz_mod(n, &key->d, u);
mpz_clear(u);
break;
case 7: /* qInv = (q^-1) mod p */
mpz_invert(n, &key->q, &key->p);
if (mpz_cmp_ui(n, 0) < 0)
mpz_add(n, n, &key->p);
passert(mpz_cmp(n, &key->p) < 0);
break;
}
}
return TRUE;
}
plog(" %s encryption not supported", pgp_sym_alg_name[s2k]);
return FALSE;
}
/*
* Parse OpenPGP signature packet defined in section 5.2.2 of RFC 2440
*/
static bool
parse_pgp_signature_packet(chunk_t *packet, pgpcert_t *cert)
static bool parse_pgp_signature_packet(chunk_t *packet, pgpcert_t *cert)
{
time_t created;
chunk_t keyid;
@@ -393,20 +236,20 @@ parse_pgp_signature_packet(chunk_t *packet, pgpcert_t *cert)
return TRUE;
/* size byte must have the value 5 */
if (pgp_size(packet, 1) != 5)
if (pgp_length(packet, 1) != 5)
{
plog(" size must be 5");
return FALSE;
}
/* signature type - 1 byte */
sig_type = (u_char)pgp_size(packet, 1);
sig_type = (u_char)pgp_length(packet, 1);
DBG(DBG_PARSING,
DBG_log("L3 - signature type: 0x%2x", sig_type)
)
/* creation date - 4 bytes */
created = (time_t)pgp_size(packet, 4);
created = (time_t)pgp_length(packet, 4);
DBG(DBG_PARSING,
DBG_log("L3 - created:");
DBG_log(" %T", &cert->created, TRUE)
@@ -420,8 +263,7 @@ parse_pgp_signature_packet(chunk_t *packet, pgpcert_t *cert)
return TRUE;
}
bool
parse_pgp(chunk_t blob, pgpcert_t *cert, RSA_private_key_t *key)
bool parse_pgp(chunk_t blob, pgpcert_t *cert, private_key_t **key)
{
DBG(DBG_PARSING,
DBG_log("L0 - PGP file:")
@@ -486,11 +328,15 @@ parse_pgp(chunk_t blob, pgpcert_t *cert, RSA_private_key_t *key)
{
case PGP_PKT_PUBLIC_KEY:
if (!parse_pgp_pubkey_packet(&packet, cert))
{
return FALSE;
}
break;
case PGP_PKT_SIGNATURE:
if (!parse_pgp_signature_packet(&packet, cert))
{
return FALSE;
}
break;
case PGP_PKT_USER_ID:
DBG(DBG_PARSING,
@@ -508,12 +354,18 @@ parse_pgp(chunk_t blob, pgpcert_t *cert, RSA_private_key_t *key)
switch (packet_type)
{
case PGP_PKT_SECRET_KEY:
if (!parse_pgp_secretkey_packet(&packet, key))
return FALSE;
*key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA,
BUILD_BLOB_PGP, packet,
BUILD_END);
break;
default:
break;
}
if (*key == NULL)
{
return FALSE;
}
}
}
}
@@ -523,8 +375,7 @@ parse_pgp(chunk_t blob, pgpcert_t *cert, RSA_private_key_t *key)
/*
* compare two OpenPGP certificates
*/
static bool
same_pgpcert(pgpcert_t *a, pgpcert_t *b)
static bool same_pgpcert(pgpcert_t *a, pgpcert_t *b)
{
return a->certificate.len == b->certificate.len &&
memeq(a->certificate.ptr, b->certificate.ptr, b->certificate.len);
@@ -533,8 +384,7 @@ same_pgpcert(pgpcert_t *a, pgpcert_t *b)
/*
* for each link pointing to the certificate increase the count by one
*/
void
share_pgpcert(pgpcert_t *cert)
void share_pgpcert(pgpcert_t *cert)
{
if (cert != NULL)
{
@@ -545,21 +395,17 @@ share_pgpcert(pgpcert_t *cert)
/*
* select the OpenPGP keyid as ID
*/
void
select_pgpcert_id(pgpcert_t *cert, struct id *end_id)
void select_pgpcert_id(pgpcert_t *cert, struct id *end_id)
{
end_id->kind = ID_KEY_ID;
end_id->name.len = PGP_FINGERPRINT_SIZE;
end_id->name.ptr = cert->fingerprint;
end_id->name.ptr = temporary_cyclic_buffer();
memcpy(end_id->name.ptr, cert->fingerprint, PGP_FINGERPRINT_SIZE);
end_id->name = cert->fingerprint->get_encoding(cert->fingerprint);
end_id->name = chunk_clone(end_id->name);
}
/*
* add an OpenPGP user/host certificate to the chained list
*/
pgpcert_t*
add_pgpcert(pgpcert_t *cert)
pgpcert_t* add_pgpcert(pgpcert_t *cert)
{
pgpcert_t *c = pgpcerts;
@@ -585,14 +431,15 @@ add_pgpcert(pgpcert_t *cert)
/* release of a certificate decreases the count by one
" the certificate is freed when the counter reaches zero
*/
void
release_pgpcert(pgpcert_t *cert)
void release_pgpcert(pgpcert_t *cert)
{
if (cert != NULL && --cert->count == 0)
{
pgpcert_t **pp = &pgpcerts;
while (*pp != cert)
{
pp = &(*pp)->next;
}
*pp = cert->next;
free_pgpcert(cert);
}
@@ -601,11 +448,12 @@ release_pgpcert(pgpcert_t *cert)
/*
* free a PGP certificate
*/
void
free_pgpcert(pgpcert_t *cert)
void free_pgpcert(pgpcert_t *cert)
{
if (cert != NULL)
{
DESTROY_IF(cert->public_key);
DESTROY_IF(cert->fingerprint);
free(cert->certificate.ptr);
free(cert);
}
@@ -614,8 +462,7 @@ free_pgpcert(pgpcert_t *cert)
/*
* list all PGP end certificates in a chained list
*/
void
list_pgp_end_certs(bool utc)
void list_pgp_end_certs(bool utc)
{
pgpcert_t *cert = pgpcerts;
time_t now;
@@ -632,19 +479,20 @@ list_pgp_end_certs(bool utc)
while (cert != NULL)
{
unsigned keysize;
char buf[BUF_LEN];
public_key_t *key = cert->public_key;
cert_t c;
c.type = CERT_PGP;
c.u.pgp = cert;
whack_log(RC_COMMENT, "%T, count: %d", &cert->installed, utc, cert->count);
datatot(cert->fingerprint, PGP_FINGERPRINT_SIZE, 'x', buf, BUF_LEN);
whack_log(RC_COMMENT, " fingerprint: %s", buf);
form_keyid(cert->publicExponent, cert->modulus, buf, &keysize);
whack_log(RC_COMMENT, " pubkey: %4d RSA Key %s%s", 8*keysize, buf,
(has_private_key(c))? ", has private key" : "");
whack_log(RC_COMMENT, " fingerprint: %Y", cert->fingerprint);
whack_log(RC_COMMENT, " pubkey: %N %4d bits%s",
key_type_names, key->get_type(key),
key->get_keysize(key) * BITS_PER_BYTE,
has_private_key(c)? ", has private key" : "");
whack_log(RC_COMMENT, " keyid: %Y",
key->get_id(key, ID_PUBKEY_INFO_SHA1));
whack_log(RC_COMMENT, " created: %T", &cert->created, utc);
whack_log(RC_COMMENT, " until: %T %s", &cert->until, utc,
check_expiry(cert->until, CA_CERT_WARNING_INTERVAL, TRUE));
+17 -17
View File
@@ -1,5 +1,7 @@
/* Support of OpenPGP certificates
* Copyright (C) 2002-2004 Andreas Steffen, Zuercher Hochschule Winterthur
* Copyright (C) 2002-2009 Andreas Steffen
*
* HSR - Hochschule fuer Technik Rapperswil
*
* 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
@@ -12,12 +14,12 @@
* for more details.
*/
#ifndef _PGP_H
#define _PGP_H
#ifndef _PGPCERT_H
#define _PGPCERT_H
#include <crypto/hashers/hasher.h>
#include "pkcs1.h"
#include <credentials/keys/private_key.h>
#include <credentials/keys/public_key.h>
/*
* Length of PGP V3 fingerprint
@@ -31,20 +33,18 @@ typedef char fingerprint_t[PGP_FINGERPRINT_SIZE];
typedef struct pgpcert pgpcert_t;
struct pgpcert {
pgpcert_t *next;
time_t installed;
int count;
chunk_t certificate;
time_t created;
time_t until;
enum pubkey_alg pubkeyAlg;
chunk_t modulus;
chunk_t publicExponent;
fingerprint_t fingerprint;
pgpcert_t *next;
time_t installed;
int count;
chunk_t certificate;
time_t created;
time_t until;
public_key_t *public_key;
identification_t *fingerprint;
};
extern const pgpcert_t empty_pgpcert;
extern bool parse_pgp(chunk_t blob, pgpcert_t *cert, RSA_private_key_t *key);
extern bool parse_pgp(chunk_t blob, pgpcert_t *cert, private_key_t **key);
extern void share_pgpcert(pgpcert_t *cert);
extern void select_pgpcert_id(pgpcert_t *cert, struct id *end_id);
extern pgpcert_t* add_pgpcert(pgpcert_t *cert);
@@ -52,4 +52,4 @@ extern void list_pgp_end_certs(bool utc);
extern void release_pgpcert(pgpcert_t *cert);
extern void free_pgpcert(pgpcert_t *cert);
#endif /* _PGP_H */
#endif /* _PGPCERT_H */
-602
View File
@@ -1,602 +0,0 @@
/* Support of PKCS#1 private key data structures
* Copyright (C) 2005 Jan Hutter, Martin Willi
* Copyright (C) 2002-2009 Andreas Steffen
*
* HSR Hochschule fuer Technik Rapperswil, Switzerland
*
* 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.
*/
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <freeswan.h>
#include <library.h>
#include <asn1/asn1.h>
#include <asn1/asn1_parser.h>
#include <asn1/oid.h>
#include <crypto/rngs/rng.h>
#include <crypto/hashers/hasher.h>
#include "constants.h"
#include "defs.h"
#include "mp_defs.h"
#include "log.h"
#include "pkcs1.h"
const struct fld RSA_private_field[] =
{
{ "Modulus", offsetof(RSA_private_key_t, pub.n) },
{ "PublicExponent", offsetof(RSA_private_key_t, pub.e) },
{ "PrivateExponent", offsetof(RSA_private_key_t, d) },
{ "Prime1", offsetof(RSA_private_key_t, p) },
{ "Prime2", offsetof(RSA_private_key_t, q) },
{ "Exponent1", offsetof(RSA_private_key_t, dP) },
{ "Exponent2", offsetof(RSA_private_key_t, dQ) },
{ "Coefficient", offsetof(RSA_private_key_t, qInv) },
};
/**
* ASN.1 definition of a PKCS#1 RSA private key
*/
static const asn1Object_t privkeyObjects[] = {
{ 0, "RSAPrivateKey", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
{ 1, "version", ASN1_INTEGER, ASN1_BODY }, /* 1 */
{ 1, "modulus", ASN1_INTEGER, ASN1_BODY }, /* 2 */
{ 1, "publicExponent", ASN1_INTEGER, ASN1_BODY }, /* 3 */
{ 1, "privateExponent", ASN1_INTEGER, ASN1_BODY }, /* 4 */
{ 1, "prime1", ASN1_INTEGER, ASN1_BODY }, /* 5 */
{ 1, "prime2", ASN1_INTEGER, ASN1_BODY }, /* 6 */
{ 1, "exponent1", ASN1_INTEGER, ASN1_BODY }, /* 7 */
{ 1, "exponent2", ASN1_INTEGER, ASN1_BODY }, /* 8 */
{ 1, "coefficient", ASN1_INTEGER, ASN1_BODY }, /* 9 */
{ 1, "otherPrimeInfos", ASN1_SEQUENCE, ASN1_OPT |
ASN1_LOOP }, /* 10 */
{ 2, "otherPrimeInfo", ASN1_SEQUENCE, ASN1_NONE }, /* 11 */
{ 3, "prime", ASN1_INTEGER, ASN1_BODY }, /* 12 */
{ 3, "exponent", ASN1_INTEGER, ASN1_BODY }, /* 13 */
{ 3, "coefficient", ASN1_INTEGER, ASN1_BODY }, /* 14 */
{ 1, "end opt or loop", ASN1_EOC, ASN1_END }, /* 15 */
{ 0, "exit", ASN1_EOC, ASN1_EXIT }
};
#define PKCS1_PRIV_KEY_VERSION 1
#define PKCS1_PRIV_KEY_MODULUS 2
#define PKCS1_PRIV_KEY_PUB_EXP 3
#define PKCS1_PRIV_KEY_COEFF 9
/**
* Forms the FreeS/WAN keyid from the public exponent e and modulus n
*/
void form_keyid(chunk_t e, chunk_t n, char* keyid, unsigned *keysize)
{
/* eliminate leading zero bytes in modulus from ASN.1 coding */
while (n.len > 1 && *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;
}
/**
* Initialize an RSA_public_key_t object
*/
void init_RSA_public_key(RSA_public_key_t *rsa, chunk_t e, chunk_t n)
{
n_to_mpz(&rsa->e, e.ptr, e.len);
n_to_mpz(&rsa->n, n.ptr, n.len);
form_keyid(e, n, rsa->keyid, &rsa->k);
}
#ifdef DEBUG
static void RSA_show_key_fields(RSA_private_key_t *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: 0x%s", p->name, buf);
}
}
/**
* debugging info that compromises security!
*/
void RSA_show_private_key(RSA_private_key_t *k)
{
RSA_show_key_fields(k, countof(RSA_private_field));
}
void RSA_show_public_key(RSA_public_key_t *k)
{
/* Kludge: pretend that it is a private key, but only display the
* first two fields (which are the public key).
*/
passert(offsetof(RSA_private_key_t, pub) == 0);
RSA_show_key_fields((RSA_private_key_t *)k, 2);
}
#endif
err_t RSA_private_key_sanity(RSA_private_key_t *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;
}
/**
* Check the equality of two RSA public keys
*/
bool same_RSA_public_key(const RSA_public_key_t *a, const RSA_public_key_t *b)
{
return a == b
|| (a->k == b->k && mpz_cmp(&a->n, &b->n) == 0 && mpz_cmp(&a->e, &b->e) == 0);
}
/**
* Parses a PKCS#1 private key
*/
bool pkcs1_parse_private_key(chunk_t blob, RSA_private_key_t *key)
{
asn1_parser_t *parser;
chunk_t object, modulus, exp;
int objectID;
bool success = FALSE;
parser = asn1_parser_create(privkeyObjects, blob);
parser->set_flags(parser, FALSE, TRUE);
while (parser->iterate(parser, &objectID, &object))
{
if (objectID == PKCS1_PRIV_KEY_VERSION)
{
if (object.len > 0 && *object.ptr != 0)
{
plog(" wrong PKCS#1 private key version");
goto end;
}
}
else if (objectID >= PKCS1_PRIV_KEY_MODULUS &&
objectID <= PKCS1_PRIV_KEY_COEFF)
{
MP_INT *u = (MP_INT *) ((char *)key
+ RSA_private_field[objectID - PKCS1_PRIV_KEY_MODULUS].offset);
n_to_mpz(u, object.ptr, object.len);
if (objectID == PKCS1_PRIV_KEY_MODULUS)
modulus = object;
else if (objectID == PKCS1_PRIV_KEY_PUB_EXP)
exp = object;
}
}
success = parser->success(parser);
end:
parser->destroy(parser);
if (success)
{
err_t ugh;
form_keyid(exp, modulus, key->pub.keyid, &key->pub.k);
ugh = RSA_private_key_sanity(key);
success = (ugh == NULL);
}
return success;
}
/**
* Compute a digest over a binary blob
*/
bool compute_digest(chunk_t tbs, int oid, chunk_t *digest)
{
hasher_t *hasher;
hash_algorithm_t alg = hasher_algorithm_from_oid(oid);
if (alg == HASH_UNKNOWN)
{
digest->len = 0;
return FALSE;
}
hasher = lib->crypto->create_hasher(lib->crypto, alg);
if (hasher == NULL)
{
digest->len = 0;
return FALSE;
}
digest->len = hasher->get_hash_size(hasher);
hasher->get_hash(hasher, tbs, digest->ptr);
hasher->destroy(hasher);
return TRUE;
}
/**
* Compute an RSA signature with PKCS#1 padding
*/
void sign_hash(const RSA_private_key_t *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);
free(ch.ptr);
mpz_clear(t1);
mpz_clear(t2);
}
/**
* Encrypt data with an RSA public key after padding
*/
chunk_t RSA_encrypt(const RSA_public_key_t *key, chunk_t in)
{
u_char padded[RSA_MAX_OCTETS];
u_char *pos = padded;
int padding = key->k - in.len - 3;
int i;
rng_t *rng;
if (padding < 8 || key->k > RSA_MAX_OCTETS)
return chunk_empty;
/* add padding according to PKCS#1 7.2.1 1.+2. */
*pos++ = 0x00;
*pos++ = 0x02;
/* pad with pseudo random bytes unequal to zero */
rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
for (i = 0; i < padding; i++)
{
rng->get_bytes(rng, padding, pos);
while (!*pos)
{
rng->get_bytes(rng, 1, pos);
}
pos++;
}
rng->destroy(rng);
/* append the padding terminator */
*pos++ = 0x00;
/* now add the data */
memcpy(pos, in.ptr, in.len);
DBG(DBG_RAW,
DBG_dump_chunk("data for rsa encryption:\n", in);
DBG_dump("padded data for rsa encryption:\n", padded, key->k)
)
/* convert chunk to integer (PKCS#1 7.2.1 3.a) */
{
chunk_t out;
mpz_t m, c;
mpz_init(c);
n_to_mpz(m, padded, key->k);
/* encrypt(PKCS#1 7.2.1 3.b) */
mpz_powm(c, m, &key->e, &key->n);
/* convert integer back to a chunk (PKCS#1 7.2.1 3.c) */
out = mpz_to_n(c, key->k);
mpz_clear(c);
mpz_clear(m);
DBG(DBG_RAW,
DBG_dump_chunk("rsa encrypted data:\n", out)
)
return out;
}
}
/**
* Decrypt data with an RSA private key and remove padding
*/
bool RSA_decrypt(const RSA_private_key_t *key, chunk_t in, chunk_t *out)
{
chunk_t padded, plaintext;
u_char *pos;
mpz_t t1, t2;
n_to_mpz(t1, in.ptr,in.len);
/* 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, &key->dP, &key->p); /* m1 = c^dP mod p */
mpz_powm(t1, t1, &key->dQ, &key->q); /* m2 = c^dQ mod Q */
mpz_sub(t2, t2, t1); /* h = qInv (m1 - m2) mod p */
mpz_mod(t2, t2, &key->p);
mpz_mul(t2, t2, &key->qInv);
mpz_mod(t2, t2, &key->p);
mpz_mul(t2, t2, &key->q); /* m = m2 + h q */
mpz_add(t1, t1, t2);
padded = mpz_to_n(t1, key->pub.k);
mpz_clear(t1);
mpz_clear(t2);
DBG(DBG_PRIVATE,
DBG_dump_chunk("rsa decrypted data with padding:\n", padded)
)
pos = padded.ptr;
/* PKCS#1 v1.5 8.1 encryption-block formatting (EB = 00 || 02 || PS || 00 || D) */
/* check for hex pattern 00 02 in decrypted message */
if ((*pos++ != 0x00) || (*(pos++) != 0x02))
{
plog("incorrect padding - probably wrong RSA key");
chunk_clear(&padded);
return FALSE;
}
padded.len -= 2;
/* the plaintext data starts after first 0x00 byte */
while (padded.len-- > 0 && *pos++ != 0x00)
if (padded.len == 0)
{
plog("no plaintext data");
free(padded.ptr);
return FALSE;
}
plaintext = chunk_create(pos, padded.len);
*out = chunk_clone(plaintext);
chunk_clear(&padded);
return TRUE;
}
/**
* Build signatureValue
*/
chunk_t pkcs1_build_signature(chunk_t tbs, int hash_alg,
const RSA_private_key_t *key, bool bit_string)
{
size_t siglen = key->pub.k;
u_char digest_buf[MAX_DIGEST_LEN];
chunk_t digest = { digest_buf, MAX_DIGEST_LEN };
chunk_t digestInfo, signatureValue;
u_char *pos;
if (!compute_digest(tbs, hash_alg, &digest))
{
return chunk_empty;
}
/* according to PKCS#1 v2.1 digest must be packaged into
* an ASN.1 structure for encryption
*/
digestInfo = asn1_wrap(ASN1_SEQUENCE, "cm"
, asn1_algorithmIdentifier(hash_alg)
, asn1_simple_object(ASN1_OCTET_STRING, digest));
/* generate the RSA signature */
if (bit_string)
{
pos = asn1_build_object(&signatureValue, ASN1_BIT_STRING, 1 + siglen);
*pos++ = 0x00;
}
else
{
pos = asn1_build_object(&signatureValue, ASN1_OCTET_STRING, siglen);
}
sign_hash(key, digestInfo.ptr, digestInfo.len, pos, siglen);
free(digestInfo.ptr);
return signatureValue;
}
/**
* Build a DER-encoded PKCS#1 private key object
*/
chunk_t pkcs1_build_private_key(const RSA_private_key_t *key)
{
chunk_t pkcs1 = asn1_wrap(ASN1_SEQUENCE, "cmmmmmmmm"
, ASN1_INTEGER_0
, asn1_integer_from_mpz(&key->pub.n)
, asn1_integer_from_mpz(&key->pub.e)
, asn1_integer_from_mpz(&key->d)
, asn1_integer_from_mpz(&key->p)
, asn1_integer_from_mpz(&key->q)
, asn1_integer_from_mpz(&key->dP)
, asn1_integer_from_mpz(&key->dQ)
, asn1_integer_from_mpz(&key->qInv));
DBG(DBG_PRIVATE,
DBG_dump_chunk("PKCS#1 encoded private key:", pkcs1)
)
return pkcs1;
}
/**
* Build a DER-encoded PKCS#1 public key object
*/
chunk_t pkcs1_build_public_key(const RSA_public_key_t *rsa)
{
return asn1_wrap(ASN1_SEQUENCE, "mm"
, asn1_integer_from_mpz(&rsa->n)
, asn1_integer_from_mpz(&rsa->e));
}
/**
* Build a DER-encoded publicKeyInfo object
*/
chunk_t pkcs1_build_publicKeyInfo(const RSA_public_key_t *rsa)
{
chunk_t publicKey;
chunk_t rawKey = pkcs1_build_public_key(rsa);
u_char *pos;
pos = asn1_build_object(&publicKey, ASN1_BIT_STRING, 1 + rawKey.len);
*pos++ = 0x00;
mv_chunk(&pos, rawKey);
return asn1_wrap(ASN1_SEQUENCE, "cm"
, asn1_algorithmIdentifier(OID_RSA_ENCRYPTION)
, publicKey);
}
void free_RSA_public_content(RSA_public_key_t *rsa)
{
mpz_clear(&rsa->n);
mpz_clear(&rsa->e);
}
void free_RSA_private_content(RSA_private_key_t *rsak)
{
free_RSA_public_content(&rsak->pub);
mpz_clear(&rsak->d);
mpz_clear(&rsak->p);
mpz_clear(&rsak->q);
mpz_clear(&rsak->dP);
mpz_clear(&rsak->dQ);
mpz_clear(&rsak->qInv);
}
-86
View File
@@ -1,86 +0,0 @@
/* Support of PKCS#1 private key data structures
* Copyright (C) 2005 Jan Hutter, Martin Willi
* Copyright (C) 2002-2005 Andreas Steffen
* Hochschule fuer Technik Rapperswil, Switzerland
*
* 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.
*/
#ifndef _PKCS1_H
#define _PKCS1_H
#include <gmp.h> /* GNU Multi Precision library */
#include "defs.h"
typedef struct RSA_public_key RSA_public_key_t;
struct RSA_public_key
{
char keyid[KEYID_BUF]; /* see ipsec_keyblobtoid(3) */
/* length of modulus n in octets: [RSA_MIN_OCTETS, RSA_MAX_OCTETS] */
unsigned k;
/* public: */
MP_INT
n, /* modulus: p * q */
e; /* exponent: relatively prime to (p-1) * (q-1) [probably small] */
};
typedef struct RSA_private_key RSA_private_key_t;
struct RSA_private_key {
struct RSA_public_key pub; /* must be at start for RSA_show_public_key */
MP_INT
d, /* private exponent: (e^-1) mod ((p-1) * (q-1)) */
/* help for Chinese Remainder Theorem speedup: */
p, /* first secret prime */
q, /* second secret prime */
dP, /* first factor's exponent: (e^-1) mod (p-1) == d mod (p-1) */
dQ, /* second factor's exponent: (e^-1) mod (q-1) == d mod (q-1) */
qInv; /* (q^-1) mod p */
};
struct fld {
const char *name;
size_t offset;
};
extern const struct fld RSA_private_field[];
#define RSA_PRIVATE_FIELD_ELEMENTS 8
extern void init_RSA_public_key(RSA_public_key_t *rsa, chunk_t e, chunk_t n);
extern bool pkcs1_parse_private_key(chunk_t blob, RSA_private_key_t *key);
extern chunk_t pkcs1_build_private_key(const RSA_private_key_t *key);
extern chunk_t pkcs1_build_public_key(const RSA_public_key_t *rsa);
extern chunk_t pkcs1_build_publicKeyInfo(const RSA_public_key_t *rsa);
extern chunk_t pkcs1_build_signature(chunk_t tbs, int hash_alg
, const RSA_private_key_t *key, bool bit_string);
extern bool compute_digest(chunk_t tbs, int alg, chunk_t *digest);
extern void sign_hash(const RSA_private_key_t *k, const u_char *hash_val
, size_t hash_len, u_char *sig_val, size_t sig_len);
extern chunk_t RSA_encrypt(const RSA_public_key_t *key, chunk_t in);
extern bool RSA_decrypt(const RSA_private_key_t *key, chunk_t in
, chunk_t *out);
extern bool same_RSA_public_key(const RSA_public_key_t *a
, const RSA_public_key_t *b);
extern void form_keyid(chunk_t e, chunk_t n, char* keyid, unsigned *keysize);
extern err_t RSA_private_key_sanity(RSA_private_key_t *k);
#ifdef DEBUG
extern void RSA_show_public_key(RSA_public_key_t *k);
extern void RSA_show_private_key(RSA_private_key_t *k);
#endif
extern void free_RSA_public_content(RSA_public_key_t *rsa);
extern void free_RSA_private_content(RSA_private_key_t *rsak);
#endif /* _PKCS1_H */
+54 -25
View File
@@ -340,6 +340,9 @@ bool pkcs7_parse_signedData(chunk_t blob, contentInfo_t *data, x509cert_t **cert
/* check the signature only if a cacert is available */
if (cacert != NULL)
{
public_key_t *key = cacert->public_key;
signature_scheme_t scheme = SIGN_RSA_EMSA_PKCS1_SHA1;
if (signerInfos == 0)
{
DBG1("no signerInfo object found");
@@ -355,15 +358,39 @@ bool pkcs7_parse_signedData(chunk_t blob, contentInfo_t *data, x509cert_t **cert
DBG1("no authenticatedAttributes object found");
return FALSE;
}
if (!check_signature(*attributes, encrypted_digest, digest_alg,
enc_alg, cacert))
if (enc_alg != OID_RSA_ENCRYPTION)
{
DBG1("invalid signature");
DBG1("only RSA digest encryption supported");
return FALSE;
}
switch (digest_alg)
{
case OID_MD5:
scheme = SIGN_RSA_EMSA_PKCS1_MD5;
break;
case OID_SHA1:
scheme = SIGN_RSA_EMSA_PKCS1_SHA1;
break;
case OID_SHA256:
scheme = SIGN_RSA_EMSA_PKCS1_SHA256;
break;
case OID_SHA384:
scheme = SIGN_RSA_EMSA_PKCS1_SHA384;
break;
case OID_SHA512:
scheme = SIGN_RSA_EMSA_PKCS1_SHA512;
break;
default:
return FALSE;
}
if (key->verify(key, scheme, *attributes, encrypted_digest))
{
DBG2("signature is valid");
}
else
{
DBG2("signature is valid");
DBG1("invalid signature");
return FALSE;
}
}
return TRUE;
@@ -374,7 +401,7 @@ bool pkcs7_parse_signedData(chunk_t blob, contentInfo_t *data, x509cert_t **cert
*/
bool pkcs7_parse_envelopedData(chunk_t blob, chunk_t *data,
chunk_t serialNumber,
const RSA_private_key_t *key)
private_key_t *key)
{
asn1_parser_t *parser;
chunk_t object;
@@ -446,7 +473,7 @@ bool pkcs7_parse_envelopedData(chunk_t blob, chunk_t *data,
}
break;
case PKCS7_ENCRYPTED_KEY:
if (!RSA_decrypt(key, object, &symmetric_key))
if (!key->decrypt(key, object, &symmetric_key))
{
DBG1("symmetric key could not be decrypted with rsa");
goto end;
@@ -579,17 +606,20 @@ chunk_t pkcs7_contentType_attribute(void)
*/
chunk_t pkcs7_messageDigest_attribute(chunk_t content, int digest_alg)
{
u_char digest_buf[MAX_DIGEST_LEN];
chunk_t digest = { digest_buf, MAX_DIGEST_LEN };
chunk_t digest;
hash_algorithm_t hash_alg;
hasher_t *hasher;
compute_digest(content, digest_alg, &digest);
hash_alg = hasher_algorithm_from_oid(digest_alg);
hasher = lib->crypto->create_hasher(lib->crypto, hash_alg);
hasher->allocate_hash(hasher, content, &digest);
return asn1_wrap(ASN1_SEQUENCE, "cm"
, ASN1_messageDigest_oid
, asn1_wrap(ASN1_SET, "m"
, asn1_simple_object(ASN1_OCTET_STRING, digest)
)
);
return asn1_wrap(ASN1_SEQUENCE, "cm",
ASN1_messageDigest_oid,
asn1_wrap(ASN1_SET, "m",
asn1_wrap(ASN1_OCTET_STRING, "m", digest)
)
);
}
/**
@@ -649,7 +679,7 @@ chunk_t pkcs7_build_issuerAndSerialNumber(const x509cert_t *cert)
*/
chunk_t pkcs7_build_signedData(chunk_t data, chunk_t attributes,
const x509cert_t *cert, int digest_alg,
const RSA_private_key_t *key)
private_key_t *key)
{
contentInfo_t pkcs7Data, signedData;
chunk_t authenticatedAttributes, encryptedDigest, signerInfo, cInfo;
@@ -658,15 +688,15 @@ chunk_t pkcs7_build_signedData(chunk_t data, chunk_t attributes,
if (attributes.ptr != NULL)
{
encryptedDigest = pkcs1_build_signature(attributes, digest_alg
, key, FALSE);
encryptedDigest = x509_build_signature(attributes, digest_alg, key,
FALSE);
authenticatedAttributes = chunk_clone(attributes);
*authenticatedAttributes.ptr = ASN1_CONTEXT_C_0;
}
else
{
encryptedDigest = (data.ptr == NULL)? chunk_empty
: pkcs1_build_signature(data, digest_alg, key, FALSE);
: x509_build_signature(data, digest_alg, key, FALSE);
authenticatedAttributes = chunk_empty;
}
@@ -705,8 +735,7 @@ chunk_t pkcs7_build_envelopedData(chunk_t data, const x509cert_t *cert, int enc_
{
encryption_algorithm_t alg;
size_t alg_key_size;
RSA_public_key_t public_key;
chunk_t symmetricKey, iv, in, out;
chunk_t symmetricKey, protectedKey, iv, in, out;
crypter_t *crypter;
alg = encryption_algorithm_from_oid(enc_alg, &alg_key_size);
@@ -759,10 +788,11 @@ chunk_t pkcs7_build_envelopedData(chunk_t data, const x509cert_t *cert, int enc_
free(in.ptr);
free(iv.ptr);
init_RSA_public_key(&public_key, cert->publicExponent, cert->modulus);
cert->public_key->encrypt(cert->public_key, symmetricKey, &protectedKey);
/* build pkcs7 enveloped data object */
{
chunk_t contentEncryptionAlgorithm = asn1_wrap(ASN1_SEQUENCE, "mm"
, asn1_build_known_oid(enc_alg)
, asn1_simple_object(ASN1_OCTET_STRING, iv));
@@ -773,7 +803,7 @@ chunk_t pkcs7_build_envelopedData(chunk_t data, const x509cert_t *cert, int enc_
, asn1_wrap(ASN1_CONTEXT_S_0, "m", out));
chunk_t encryptedKey = asn1_wrap(ASN1_OCTET_STRING, "m"
, RSA_encrypt(&public_key, symmetricKey));
, protectedKey);
chunk_t recipientInfo = asn1_wrap(ASN1_SEQUENCE, "cmcm"
, ASN1_INTEGER_0
@@ -793,7 +823,6 @@ chunk_t pkcs7_build_envelopedData(chunk_t data, const x509cert_t *cert, int enc_
cInfo = pkcs7_build_contentInfo(&envelopedData);
DBG3("envelopedData %B", &cInfo);
free_RSA_public_content(&public_key);
free(envelopedData.content.ptr);
free(symmetricKey.ptr);
return cInfo;
+5 -5
View File
@@ -1,6 +1,7 @@
/* Support of PKCS#7 data structures
* Copyright (C) 2005 Jan Hutter, Martin Willi
* Copyright (C) 2002-2005 Andreas Steffen
* Copyright (C) 2002-2009 Andreas Steffen
*
* Hochschule fuer Technik Rapperswil, Switzerland
*
* This program is free software; you can redistribute it and/or modify it
@@ -18,9 +19,8 @@
#define _PKCS7_H
#include <crypto/crypters/crypter.h>
#include <credentials/keys/private_key.h>
#include "defs.h"
#include "pkcs1.h"
#include "x509.h"
/* Access structure for a PKCS#7 ContentInfo object */
@@ -39,12 +39,12 @@ extern bool pkcs7_parse_contentInfo(chunk_t blob, u_int level0,
extern bool pkcs7_parse_signedData(chunk_t blob, contentInfo_t *data,
x509cert_t **cert, chunk_t *attributes, const x509cert_t *cacert);
extern bool pkcs7_parse_envelopedData(chunk_t blob, chunk_t *data,
chunk_t serialNumber, const RSA_private_key_t *key);
chunk_t serialNumber, private_key_t *key);
extern chunk_t pkcs7_contentType_attribute(void);
extern chunk_t pkcs7_messageDigest_attribute(chunk_t content, int digest_alg);
extern chunk_t pkcs7_build_issuerAndSerialNumber(const x509cert_t *cert);
extern chunk_t pkcs7_build_signedData(chunk_t data, chunk_t attributes,
const x509cert_t *cert, int digest_alg, const RSA_private_key_t *key);
const x509cert_t *cert, int digest_alg, private_key_t *key);
extern chunk_t pkcs7_build_envelopedData(chunk_t data, const x509cert_t *cert,
int enc_alg);
+5 -4
View File
@@ -234,10 +234,11 @@ key_add_request(const whack_message_t *msg)
}
else
{
ugh = add_public_key(&keyid, DAL_LOCAL, msg->pubkey_alg
, &msg->keyval, &pubkeys);
if (ugh != NULL)
loglog(RC_LOG_SERIOUS, "%s", ugh);
if (!add_public_key(&keyid, DAL_LOCAL, msg->pubkey_alg, msg->keyval,
&pubkeys))
{
loglog(RC_LOG_SERIOUS, "failed to add public key");
}
}
}
}
+126 -224
View File
@@ -35,7 +35,6 @@
#include "mp_defs.h"
#include "log.h"
#include "id.h"
#include "pkcs1.h"
#include "x509.h"
#include "crl.h"
#include "ca.h"
@@ -198,36 +197,33 @@ static const asn1Object_t pubkeyObjects[] = {
* ASN.1 definition of an X.509v3 x509_cert
*/
static const asn1Object_t certObjects[] = {
{ 0, "certificate", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */
{ 1, "tbsCertificate", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */
{ 2, "DEFAULT v1", ASN1_CONTEXT_C_0, ASN1_DEF }, /* 2 */
{ 3, "version", ASN1_INTEGER, ASN1_BODY }, /* 3 */
{ 2, "serialNumber", ASN1_INTEGER, ASN1_BODY }, /* 4 */
{ 2, "signature", ASN1_EOC, ASN1_RAW }, /* 5 */
{ 2, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 6 */
{ 2, "validity", ASN1_SEQUENCE, ASN1_NONE }, /* 7 */
{ 3, "notBefore", ASN1_EOC, ASN1_RAW }, /* 8 */
{ 3, "notAfter", ASN1_EOC, ASN1_RAW }, /* 9 */
{ 2, "subject", ASN1_SEQUENCE, ASN1_OBJ }, /* 10 */
{ 2, "subjectPublicKeyInfo", ASN1_SEQUENCE, ASN1_NONE }, /* 11 */
{ 3, "algorithm", ASN1_EOC, ASN1_RAW }, /* 12 */
{ 3, "subjectPublicKey", ASN1_BIT_STRING, ASN1_BODY }, /* 13 */
{ 2, "issuerUniqueID", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 14 */
{ 2, "end opt", ASN1_EOC, ASN1_END }, /* 15 */
{ 2, "subjectUniqueID", ASN1_CONTEXT_C_2, ASN1_OPT }, /* 16 */
{ 2, "end opt", ASN1_EOC, ASN1_END }, /* 17 */
{ 2, "optional extensions", ASN1_CONTEXT_C_3, ASN1_OPT }, /* 18 */
{ 3, "extensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 19 */
{ 4, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 20 */
{ 5, "extnID", ASN1_OID, ASN1_BODY }, /* 21 */
{ 5, "critical", ASN1_BOOLEAN, ASN1_DEF |
ASN1_BODY }, /* 22 */
{ 5, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 23 */
{ 3, "end loop", ASN1_EOC, ASN1_END }, /* 24 */
{ 2, "end opt", ASN1_EOC, ASN1_END }, /* 25 */
{ 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 26 */
{ 1, "signatureValue", ASN1_BIT_STRING, ASN1_BODY }, /* 27 */
{ 0, "exit", ASN1_EOC, ASN1_EXIT }
{ 0, "x509", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */
{ 1, "tbsCertificate", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */
{ 2, "DEFAULT v1", ASN1_CONTEXT_C_0, ASN1_DEF }, /* 2 */
{ 3, "version", ASN1_INTEGER, ASN1_BODY }, /* 3 */
{ 2, "serialNumber", ASN1_INTEGER, ASN1_BODY }, /* 4 */
{ 2, "signature", ASN1_EOC, ASN1_RAW }, /* 5 */
{ 2, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 6 */
{ 2, "validity", ASN1_SEQUENCE, ASN1_NONE }, /* 7 */
{ 3, "notBefore", ASN1_EOC, ASN1_RAW }, /* 8 */
{ 3, "notAfter", ASN1_EOC, ASN1_RAW }, /* 9 */
{ 2, "subject", ASN1_SEQUENCE, ASN1_OBJ }, /* 10 */
{ 2, "subjectPublicKeyInfo",ASN1_SEQUENCE, ASN1_RAW }, /* 11 */
{ 2, "issuerUniqueID", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 12 */
{ 2, "end opt", ASN1_EOC, ASN1_END }, /* 13 */
{ 2, "subjectUniqueID", ASN1_CONTEXT_C_2, ASN1_OPT }, /* 14 */
{ 2, "end opt", ASN1_EOC, ASN1_END }, /* 15 */
{ 2, "optional extensions", ASN1_CONTEXT_C_3, ASN1_OPT }, /* 16 */
{ 3, "extensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 17 */
{ 4, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 18 */
{ 5, "extnID", ASN1_OID, ASN1_BODY }, /* 19 */
{ 5, "critical", ASN1_BOOLEAN, ASN1_DEF|ASN1_BODY }, /* 20 */
{ 5, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 21 */
{ 3, "end loop", ASN1_EOC, ASN1_END }, /* 22 */
{ 2, "end opt", ASN1_EOC, ASN1_END }, /* 23 */
{ 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 24 */
{ 1, "signatureValue", ASN1_BIT_STRING, ASN1_BODY }, /* 25 */
{ 0, "exit", ASN1_EOC, ASN1_EXIT }
};
#define X509_OBJ_CERTIFICATE 0
#define X509_OBJ_TBS_CERTIFICATE 1
@@ -238,13 +234,12 @@ static const asn1Object_t certObjects[] = {
#define X509_OBJ_NOT_BEFORE 8
#define X509_OBJ_NOT_AFTER 9
#define X509_OBJ_SUBJECT 10
#define X509_OBJ_SUBJECT_PUBLIC_KEY_ALGORITHM 12
#define X509_OBJ_SUBJECT_PUBLIC_KEY 13
#define X509_OBJ_EXTN_ID 21
#define X509_OBJ_CRITICAL 22
#define X509_OBJ_EXTN_VALUE 23
#define X509_OBJ_ALGORITHM 26
#define X509_OBJ_SIGNATURE 27
#define X509_OBJ_SUBJECT_PUBLIC_KEY_INFO 11
#define X509_OBJ_EXTN_ID 19
#define X509_OBJ_CRITICAL 20
#define X509_OBJ_EXTN_VALUE 21
#define X509_OBJ_ALGORITHM 24
#define X509_OBJ_SIGNATURE 25
const x509cert_t empty_x509cert = {
NULL , /* *next */
@@ -262,11 +257,7 @@ const x509cert_t empty_x509cert = {
0 , /* notBefore */
0 , /* notAfter */
{ NULL, 0 } , /* subject */
/* subjectPublicKeyInfo */
OID_UNKNOWN , /* subjectPublicKeyAlgorithm */
{ NULL, 0 } , /* subjectPublicKey */
{ NULL, 0 } , /* modulus */
{ NULL, 0 } , /* publicExponent */
NULL , /* public_key */
/* issuerUniqueID */
/* subjectUniqueID */
/* extensions */
@@ -1140,13 +1131,19 @@ chunk_t build_subjectAltNames(generalName_t *subjectAltNames)
/**
* Build a to-be-signed X.509 certificate body
*/
static chunk_t build_tbs_x509cert(x509cert_t *cert, const RSA_public_key_t *rsa)
static chunk_t build_tbs_x509cert(x509cert_t *cert, public_key_t *rsa)
{
/* version is always X.509v3 */
chunk_t version = asn1_simple_object(ASN1_CONTEXT_C_0, ASN1_INTEGER_2);
chunk_t extensions = chunk_empty;
chunk_t key = rsa->get_encoding(rsa);
chunk_t keyInfo = asn1_wrap(ASN1_SEQUENCE, "cm",
asn1_algorithmIdentifier(OID_RSA_ENCRYPTION),
asn1_bitstring("m", key));
if (cert->subjectAltName != NULL)
{
extensions = asn1_wrap(ASN1_CONTEXT_C_3, "m"
@@ -1156,7 +1153,7 @@ static chunk_t build_tbs_x509cert(x509cert_t *cert, const RSA_public_key_t *rsa)
return asn1_wrap(ASN1_SEQUENCE, "mmccmcmm"
, version
, asn1_simple_object(ASN1_INTEGER, cert->serialNumber)
, asn1_integer("c", cert->serialNumber)
, asn1_algorithmIdentifier(cert->sigAlg)
, cert->issuer
, asn1_wrap(ASN1_SEQUENCE, "mm"
@@ -1164,7 +1161,7 @@ static chunk_t build_tbs_x509cert(x509cert_t *cert, const RSA_public_key_t *rsa)
, asn1_from_time(&cert->notAfter, ASN1_UTCTIME)
)
, cert->subject
, pkcs1_build_publicKeyInfo(rsa)
, keyInfo
, extensions
);
}
@@ -1172,13 +1169,13 @@ static chunk_t build_tbs_x509cert(x509cert_t *cert, const RSA_public_key_t *rsa)
/**
* Build a DER-encoded X.509 certificate
*/
void build_x509cert(x509cert_t *cert, const RSA_public_key_t *cert_key,
const RSA_private_key_t *signer_key)
void build_x509cert(x509cert_t *cert, public_key_t *cert_key,
private_key_t *signer_key)
{
chunk_t tbs_cert = build_tbs_x509cert(cert, cert_key);
chunk_t signature = pkcs1_build_signature(tbs_cert, cert->sigAlg
, signer_key, TRUE);
chunk_t signature = x509_build_signature(tbs_cert, cert->sigAlg
, signer_key, TRUE);
cert->certificate = asn1_wrap(ASN1_SEQUENCE, "mcm"
, tbs_cert
@@ -1210,6 +1207,7 @@ void free_x509cert(x509cert_t *cert)
{
if (cert != NULL)
{
DESTROY_IF(cert->public_key);
free_generalNames(cert->subjectAltName, FALSE);
free_generalNames(cert->crlDistributionPoints, FALSE);
free(cert->certificate.ptr);
@@ -1318,111 +1316,75 @@ void store_x509certs(x509cert_t **firstcert, bool strict)
}
/**
* Decrypts an RSA signature using the issuer's certificate
* Check if a signature over binary blob is genuine
*/
static bool decrypt_sig(chunk_t sig, int alg, const x509cert_t *issuer_cert,
chunk_t *digest)
bool x509_check_signature(chunk_t tbs, chunk_t sig, int algorithm,
const x509cert_t *issuer_cert)
{
switch (alg)
public_key_t *key = issuer_cert->public_key;
signature_scheme_t scheme = SIGN_DEFAULT;
switch (algorithm)
{
chunk_t decrypted;
case OID_RSA_ENCRYPTION:
case OID_MD2_WITH_RSA:
case OID_MD5_WITH_RSA:
scheme = SIGN_RSA_EMSA_PKCS1_MD5;
break;
case OID_SHA1_WITH_RSA:
case OID_SHA1_WITH_RSA_OIW:
scheme = SIGN_RSA_EMSA_PKCS1_SHA1;
break;
case OID_SHA256_WITH_RSA:
scheme = SIGN_RSA_EMSA_PKCS1_SHA256;
break;
case OID_SHA384_WITH_RSA:
scheme = SIGN_RSA_EMSA_PKCS1_SHA384;
break;
case OID_SHA512_WITH_RSA:
{
mpz_t s;
RSA_public_key_t rsa;
init_RSA_public_key(&rsa, issuer_cert->publicExponent
, issuer_cert->modulus);
/* decrypt the signature s = s^e mod n */
n_to_mpz(s, sig.ptr, sig.len);
mpz_powm(s, s, &rsa.e, &rsa.n);
/* convert back to bytes */
decrypted = mpz_to_n(s, rsa.k);
DBG(DBG_PARSING,
DBG_dump_chunk(" decrypted signature: ", decrypted)
)
/* copy the least significant bits of decrypted signature
* into the digest string
*/
memcpy(digest->ptr, decrypted.ptr + decrypted.len - digest->len,
digest->len);
/* free memory */
free_RSA_public_content(&rsa);
free(decrypted.ptr);
mpz_clear(s);
return TRUE;
}
scheme = SIGN_RSA_EMSA_PKCS1_SHA512;
break;
case OID_ECDSA_WITH_SHA1:
scheme = SIGN_ECDSA_WITH_SHA1;
break;
default:
digest->len = 0;
return FALSE;
}
return key->verify(key, scheme, tbs, sig);
}
/**
* Check if a signature over binary blob is genuine
* Build an ASN.1 encoded PKCS#1 signature over a binary blob
*/
bool check_signature(chunk_t tbs, chunk_t sig, int digest_alg, int enc_alg,
const x509cert_t *issuer_cert)
chunk_t x509_build_signature(chunk_t tbs, int hash_alg, private_key_t *key,
bool bit_string)
{
u_char digest_buf[MAX_DIGEST_LEN];
u_char decrypted_buf[MAX_DIGEST_LEN];
chunk_t digest = {digest_buf, MAX_DIGEST_LEN};
chunk_t decrypted = {decrypted_buf, MAX_DIGEST_LEN};
signature_scheme_t scheme = SIGN_DEFAULT;
chunk_t signature;
DBG(DBG_PARSING,
if (digest_alg != OID_UNKNOWN)
{
DBG_log("signature digest algorithm: '%s'",oid_names[digest_alg].name);
}
else
{
DBG_log("unknown signature digest algorithm");
}
)
if (!compute_digest(tbs, digest_alg, &digest))
switch (hash_alg)
{
plog(" digest algorithm not supported");
return FALSE;
case OID_MD5:
scheme = SIGN_RSA_EMSA_PKCS1_MD5;
break;
case OID_SHA1:
scheme = SIGN_RSA_EMSA_PKCS1_SHA1;
break;
case OID_SHA256:
scheme = SIGN_RSA_EMSA_PKCS1_SHA256;
break;
case OID_SHA384:
scheme = SIGN_RSA_EMSA_PKCS1_SHA384;
break;
case OID_SHA512:
scheme = SIGN_RSA_EMSA_PKCS1_SHA512;
break;
default:
return chunk_empty;
}
DBG(DBG_PARSING,
DBG_dump_chunk(" digest:", digest)
)
decrypted.len = digest.len; /* we want the same digest length */
DBG(DBG_PARSING,
if (enc_alg != OID_UNKNOWN)
{
DBG_log("signature encryption algorithm: '%s'",oid_names[enc_alg].name);
}
else
{
DBG_log("unknown signature encryption algorithm");
}
)
if (!decrypt_sig(sig, enc_alg, issuer_cert, &decrypted))
if (!key->sign(key, scheme, tbs, &signature))
{
plog(" decryption algorithm not supported");
return FALSE;
}
/* check if digests are equal */
return memeq(decrypted.ptr, digest.ptr, digest.len);
return chunk_empty;
}
return (bit_string) ? asn1_bitstring("m", signature)
: asn1_wrap(ASN1_OCTET_STRING, "m", signature);
}
/**
@@ -1489,15 +1451,17 @@ void gntoid(struct id *id, const generalName_t *gn)
*/
bool compute_subjectKeyID(x509cert_t *cert, chunk_t subjectKeyID)
{
hasher_t *hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
identification_t *keyid;
chunk_t encoding;
if (hasher == NULL)
keyid = cert->public_key->get_id(cert->public_key, ID_PUBKEY_SHA1);
if (keyid == NULL)
{
plog(" no SHA-1 hasher available to compute subjectKeyID");
plog(" unable to compute subjectKeyID");
return FALSE;
}
hasher->get_hash(hasher, cert->subjectPublicKey, subjectKeyID.ptr);
hasher->destroy(hasher);
encoding = keyid->get_encoding(keyid);
memcpy(subjectKeyID.ptr, encoding.ptr, subjectKeyID.len);
return TRUE;
}
@@ -1824,50 +1788,6 @@ static generalName_t* parse_crlDistributionPoints(chunk_t blob, int level0)
return top_gn;
}
/**
* Parses an RSA public key
*/
bool parse_RSA_public_key(chunk_t blob, u_int level0, x509cert_t *cert)
{
asn1_parser_t *parser;
chunk_t object;
int objectID;
bool success = FALSE;
parser = asn1_parser_create(pubkeyObjects, blob);
parser->set_top_level(parser, level0);
while (parser->iterate(parser, &objectID, &object))
{
switch (objectID) {
case PUB_KEY_RSA_PUBLIC_KEY:
cert->subjectPublicKey = object;
break;
case PUB_KEY_MODULUS:
if (object.len < RSA_MIN_OCTETS + 1)
{
plog(" " RSA_MIN_OCTETS_UGH);
goto end;
}
if (object.len > RSA_MAX_OCTETS + (size_t)(*object.ptr == 0x00))
{
plog(" " RSA_MAX_OCTETS_UGH);
goto end;
}
cert->modulus = object;
break;
case PUB_KEY_EXPONENT:
cert->publicExponent = object;
break;
}
}
success = parser->success(parser);
end:
parser->destroy(parser);
return success;
}
/**
* Parses an X.509v3 certificate
*/
@@ -1927,30 +1847,11 @@ bool parse_x509cert(chunk_t blob, u_int level0, x509cert_t *cert)
DBG_log(" '%s'",buf)
)
break;
case X509_OBJ_SUBJECT_PUBLIC_KEY_ALGORITHM:
if (asn1_parse_algorithmIdentifier(object, level, NULL) == OID_RSA_ENCRYPTION)
case X509_OBJ_SUBJECT_PUBLIC_KEY_INFO:
cert->public_key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY,
KEY_ANY, BUILD_BLOB_ASN1_DER, object, BUILD_END);
if (cert->public_key == NULL)
{
cert->subjectPublicKeyAlgorithm = PUBKEY_ALG_RSA;
}
else
{
plog(" unsupported public key algorithm");
goto end;
}
break;
case X509_OBJ_SUBJECT_PUBLIC_KEY:
if (object.len > 0 && *object.ptr == 0x00)
{
/* skip initial bit string octet defining 0 unused bits */
object = chunk_skip(object, 1);
if (!parse_RSA_public_key(object, level, cert))
{
goto end;
}
}
else
{
plog(" invalid RSA public key format");
goto end;
}
break;
@@ -2116,8 +2017,8 @@ bool verify_x509cert(const x509cert_t *cert, bool strict, time_t *until)
DBG_log("issuer cacert found")
)
if (!check_signature(cert->tbsCertificate, cert->signature
, cert->algorithm, cert->algorithm, issuer_cert))
if (!x509_check_signature(cert->tbsCertificate, cert->signature,
cert->algorithm, issuer_cert))
{
plog("certificate signature is invalid");
unlock_authcert_list("verify_x509cert");
@@ -2220,9 +2121,8 @@ void list_x509cert_chain(const char *caption, x509cert_t* cert,
{
if (auth_flags == AUTH_NONE || (auth_flags & cert->authority_flags))
{
unsigned keysize;
char keyid[KEYID_BUF];
u_char buf[BUF_LEN];
public_key_t *key = cert->public_key;
cert_t c;
c.type = CERT_X509_SIGNATURE;
@@ -2242,36 +2142,38 @@ void list_x509cert_chain(const char *caption, x509cert_t* cert,
whack_log(RC_COMMENT, " subject: '%s'", buf);
dntoa(buf, BUF_LEN, cert->issuer);
whack_log(RC_COMMENT, " issuer: '%s'", buf);
datatot(cert->serialNumber.ptr, cert->serialNumber.len, ':'
, buf, BUF_LEN);
datatot(cert->serialNumber.ptr, cert->serialNumber.len, ':',
buf, BUF_LEN);
whack_log(RC_COMMENT, " serial: %s", buf);
form_keyid(cert->publicExponent, cert->modulus, keyid, &keysize);
whack_log(RC_COMMENT, " pubkey: %4d RSA Key %s%s"
, 8*keysize, keyid
, cert->smartcard ? ", on smartcard" :
(has_private_key(c)? ", has private key" : ""));
whack_log(RC_COMMENT, " validity: not before %T %s",
&cert->notBefore, utc,
(cert->notBefore < now)?"ok":"fatal (not valid yet)");
whack_log(RC_COMMENT, " not after %T %s",
&cert->notAfter, utc,
check_expiry(cert->notAfter, CA_CERT_WARNING_INTERVAL, TRUE));
whack_log(RC_COMMENT, " pubkey: %N %4d bits%s",
key_type_names, key->get_type(key),
key->get_keysize(key) * BITS_PER_BYTE,
cert->smartcard ? ", on smartcard" :
(has_private_key(c)? ", has private key" : ""));
whack_log(RC_COMMENT, " keyid: %Y",
key->get_id(key, ID_PUBKEY_INFO_SHA1));
if (cert->subjectKeyID.ptr != NULL)
{
datatot(cert->subjectKeyID.ptr, cert->subjectKeyID.len, ':'
, buf, BUF_LEN);
datatot(cert->subjectKeyID.ptr, cert->subjectKeyID.len, ':',
buf, BUF_LEN);
whack_log(RC_COMMENT, " subjkey: %s", buf);
}
if (cert->authKeyID.ptr != NULL)
{
datatot(cert->authKeyID.ptr, cert->authKeyID.len, ':'
, buf, BUF_LEN);
datatot(cert->authKeyID.ptr, cert->authKeyID.len, ':',
buf, BUF_LEN);
whack_log(RC_COMMENT, " authkey: %s", buf);
}
if (cert->authKeySerialNumber.ptr != NULL)
{
datatot(cert->authKeySerialNumber.ptr, cert->authKeySerialNumber.len
, ':', buf, BUF_LEN);
datatot(cert->authKeySerialNumber.ptr,
cert->authKeySerialNumber.len, ':', buf, BUF_LEN);
whack_log(RC_COMMENT, " aserial: %s", buf);
}
}
+52 -52
View File
@@ -2,7 +2,7 @@
* Copyright (C) 2000 Andreas Hess, Patric Lichtsteiner, Roger Wegmann
* Copyright (C) 2001 Marco Bertossa, Andreas Schleiss
* Copyright (C) 2002 Mario Strasser
* Copyright (C) 2000-2004 Andreas Steffen, Zuercher Hochschule Winterthur
* Copyright (C) 2000-2009 Andreas Steffen, Hochschule fuer Technik Rapperswil
*
* 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
@@ -18,8 +18,10 @@
#ifndef _X509_H
#define _X509_H
#include <credentials/keys/public_key.h>
#include <credentials/keys/private_key.h>
#include "constants.h"
#include "pkcs1.h"
#include "id.h"
/* Definition of generalNames kinds */
@@ -51,46 +53,42 @@ struct generalName {
typedef struct x509cert x509cert_t;
struct x509cert {
x509cert_t *next;
time_t installed;
int count;
bool smartcard;
u_char authority_flags;
chunk_t certificate;
chunk_t tbsCertificate;
u_int version;
chunk_t serialNumber;
/* signature */
int sigAlg;
chunk_t issuer;
/* validity */
time_t notBefore;
time_t notAfter;
chunk_t subject;
/* subjectPublicKeyInfo */
enum pubkey_alg subjectPublicKeyAlgorithm;
chunk_t subjectPublicKey;
chunk_t modulus;
chunk_t publicExponent;
/* issuerUniqueID */
/* subjectUniqueID */
/* v3 extensions */
/* extension */
/* extension */
/* extnID */
/* critical */
/* extnValue */
bool isCA;
bool isOcspSigner; /* ocsp */
chunk_t subjectKeyID;
chunk_t authKeyID;
chunk_t authKeySerialNumber;
chunk_t accessLocation; /* ocsp */
generalName_t *subjectAltName;
generalName_t *crlDistributionPoints;
/* signatureAlgorithm */
int algorithm;
chunk_t signature;
x509cert_t *next;
time_t installed;
int count;
bool smartcard;
u_char authority_flags;
chunk_t certificate;
chunk_t tbsCertificate;
u_int version;
chunk_t serialNumber;
/* signature */
int sigAlg;
chunk_t issuer;
/* validity */
time_t notBefore;
time_t notAfter;
chunk_t subject;
public_key_t *public_key;
/* issuerUniqueID */
/* subjectUniqueID */
/* v3 extensions */
/* extension */
/* extension */
/* extnID */
/* critical */
/* extnValue */
bool isCA;
bool isOcspSigner; /* ocsp */
chunk_t subjectKeyID;
chunk_t authKeyID;
chunk_t authKeySerialNumber;
chunk_t accessLocation; /* ocsp */
generalName_t *subjectAltName;
generalName_t *crlDistributionPoints;
/* signatureAlgorithm */
int algorithm;
chunk_t signature;
};
/* used for initialization */
@@ -104,8 +102,8 @@ extern bool same_x509cert(const x509cert_t *a, const x509cert_t *b);
extern void hex_str(chunk_t bin, chunk_t *str);
extern int dn_count_wildcards(chunk_t dn);
extern int dntoa(char *dst, size_t dstlen, chunk_t dn);
extern int dntoa_or_null(char *dst, size_t dstlen, chunk_t dn
, const char* null_dn);
extern int dntoa_or_null(char *dst, size_t dstlen, chunk_t dn,
const char* null_dn);
extern err_t atodn(char *src, chunk_t *dn);
extern void gntoid(struct id *id, const generalName_t *gn);
extern bool compute_subjectKeyID(x509cert_t *cert, chunk_t subjectKeyID);
@@ -116,21 +114,23 @@ extern void parse_authorityKeyIdentifier(chunk_t blob, int level0
, chunk_t *authKeyID, chunk_t *authKeySerialNumber);
extern chunk_t get_directoryName(chunk_t blob, int level, bool implicit);
extern err_t check_validity(const x509cert_t *cert, time_t *until);
extern bool check_signature(chunk_t tbs, chunk_t sig, int digest_alg
, int enc_alg, const x509cert_t *issuer_cert);
extern bool x509_check_signature(chunk_t tbs, chunk_t sig, int algorithm,
const x509cert_t *issuer_cert);
extern chunk_t x509_build_signature(chunk_t tbs, int hash_alg, private_key_t *key,
bool bit_string);
extern bool verify_x509cert(const x509cert_t *cert, bool strict, time_t *until);
extern x509cert_t* add_x509cert(x509cert_t *cert);
extern x509cert_t* get_x509cert(chunk_t issuer, chunk_t serial, chunk_t keyid
, x509cert_t* chain);
extern void build_x509cert(x509cert_t *cert, const RSA_public_key_t *cert_key
, const RSA_private_key_t *signer_key);
extern x509cert_t* get_x509cert(chunk_t issuer, chunk_t serial, chunk_t keyid,
x509cert_t* chain);
extern void build_x509cert(x509cert_t *cert, public_key_t *cert_key,
private_key_t *signer_key);
extern chunk_t build_subjectAltNames(generalName_t *subjectAltNames);
extern void share_x509cert(x509cert_t *cert);
extern void release_x509cert(x509cert_t *cert);
extern void free_x509cert(x509cert_t *cert);
extern void store_x509certs(x509cert_t **firstcert, bool strict);
extern void list_x509cert_chain(const char *caption, x509cert_t* cert
, u_char auth_flags, bool utc);
extern void list_x509cert_chain(const char *caption, x509cert_t* cert,
u_char auth_flags, bool utc);
extern void list_x509_end_certs(bool utc);
extern void free_generalNames(generalName_t* gn, bool free_name);