pluto and scepclient use private and public key plugins of libstrongswan
This commit is contained in:
committed by
Martin Willi
parent
b00fbdb55a
commit
8b799d55ce
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
+15
-20
@@ -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
@@ -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");
|
||||
|
||||
@@ -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));
|
||||
@@ -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 */
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user