Added support for client certificates (both client-side and server-side, but still missing an API for extracting the client identity from the certificate).

This commit is contained in:
Thomas Pornin 2016-12-10 17:35:06 +01:00
parent e9ce2f4e8c
commit e61ad42191
27 changed files with 4441 additions and 1482 deletions

View file

@ -279,6 +279,11 @@ void list_names(void);
*/
const char *ec_curve_name(int curve);
/*
* Get the symbolic name for a hash function name (by ID).
*/
const char *hash_function_name(int id);
/*
* Read a file completely. The returned block is allocated with xmalloc()
* and must be released by the caller.
@ -342,6 +347,12 @@ pem_object *decode_pem(const void *src, size_t len, size_t *num);
*/
br_x509_certificate *read_certificates(const char *fname, size_t *num);
/*
* Release certificates. This releases all certificate data arrays,
* and the whole array as well.
*/
void free_certificates(br_x509_certificate *certs, size_t num);
/*
* Interpret a certificate as a trust anchor. The trust anchor is
* newly allocated with xmalloc() and the caller must release it.
@ -369,6 +380,12 @@ void free_ta_contents(br_x509_trust_anchor *ta);
*/
size_t read_trust_anchors(anchor_list *dst, const char *fname);
/*
* Get the "signer key type" for the certificate (key type of the
* issuing CA). On error, this prints a message on stderr, and returns 0.
*/
int get_cert_signer_algo(br_x509_certificate *xc);
/*
* Special "no anchor" X.509 validator that wraps around another X.509
* validator and turns "not trusted" error codes into success. This is
@ -408,6 +425,20 @@ private_key *read_private_key(const char *fname);
*/
void free_private_key(private_key *sk);
/*
* Get the encoded OID for a given hash function (to use with PKCS#1
* signatures). If the hash function ID is 0 (for MD5+SHA-1), or if
* the ID is not one of the SHA-* functions (SHA-1, SHA-224, SHA-256,
* SHA-384, SHA-512), then this function returns NULL.
*/
const unsigned char *get_hash_oid(int id);
/*
* Get a hash implementation by ID. This returns NULL if the hash
* implementation is not available.
*/
const br_hash_class *get_hash_impl(int id);
/*
* Find the symbolic name and the description for an error. If 'err' is
* recognised then the error symbolic name is returned; if 'comment' is

View file

@ -53,8 +53,8 @@ certificate_to_trust_anchor_inner(br_x509_trust_anchor *ta,
VEC_CLEAR(vdn);
return -1;
}
ta->dn = VEC_TOARRAY(vdn);
ta->dn_len = VEC_LEN(vdn);
ta->dn.data = VEC_TOARRAY(vdn);
ta->dn.len = VEC_LEN(vdn);
VEC_CLEAR(vdn);
ta->flags = 0;
if (br_x509_decoder_isCA(&dc)) {
@ -76,7 +76,7 @@ certificate_to_trust_anchor_inner(br_x509_trust_anchor *ta,
break;
default:
fprintf(stderr, "ERROR: unsupported public key type in CA\n");
xfree(ta->dn);
xfree(ta->dn.data);
return -1;
}
return 0;
@ -99,7 +99,7 @@ certificate_to_trust_anchor(br_x509_certificate *xc)
void
free_ta_contents(br_x509_trust_anchor *ta)
{
xfree(ta->dn);
xfree(ta->dn.data);
switch (ta->pkey.key_type) {
case BR_KEYTYPE_RSA:
xfree(ta->pkey.key.rsa.n);
@ -137,15 +137,32 @@ read_trust_anchors(anchor_list *dst, const char *fname)
return num;
}
/* see brssl.h */
int
get_cert_signer_algo(br_x509_certificate *xc)
{
br_x509_decoder_context dc;
int err;
br_x509_decoder_init(&dc, 0, 0);
br_x509_decoder_push(&dc, xc->data, xc->data_len);
err = br_x509_decoder_last_error(&dc);
if (err != 0) {
fprintf(stderr,
"ERROR: certificate decoding failed with error %d\n",
-err);
return 0;
}
return br_x509_decoder_get_signer_key_type(&dc);
}
static void
xwc_start_chain(const br_x509_class **ctx,
unsigned expected_key_type, const char *server_name)
xwc_start_chain(const br_x509_class **ctx, const char *server_name)
{
x509_noanchor_context *xwc;
xwc = (x509_noanchor_context *)ctx;
(*xwc->inner)->start_chain(xwc->inner,
expected_key_type, server_name);
(*xwc->inner)->start_chain(xwc->inner, server_name);
}
static void
@ -190,12 +207,12 @@ xwc_end_chain(const br_x509_class **ctx)
}
static const br_x509_pkey *
xwc_get_pkey(const br_x509_class *const *ctx)
xwc_get_pkey(const br_x509_class *const *ctx, unsigned *usages)
{
x509_noanchor_context *xwc;
xwc = (x509_noanchor_context *)ctx;
return (*xwc->inner)->get_pkey(xwc->inner);
return (*xwc->inner)->get_pkey(xwc->inner, usages);
}
/* see brssl.h */

View file

@ -117,6 +117,308 @@ host_connect(const char *host, const char *port, int verbose)
return fd;
}
typedef struct {
const br_ssl_client_certificate_class *vtable;
int verbose;
br_x509_certificate *chain;
size_t chain_len;
private_key *sk;
int issuer_key_type;
} ccert_context;
static void
cc_start_name_list(const br_ssl_client_certificate_class **pctx)
{
ccert_context *zc;
zc = (ccert_context *)pctx;
if (zc->verbose) {
fprintf(stderr, "Server requests a client certificate.\n");
fprintf(stderr, "--- anchor DN list start ---\n");
}
}
static void
cc_start_name(const br_ssl_client_certificate_class **pctx, size_t len)
{
ccert_context *zc;
zc = (ccert_context *)pctx;
if (zc->verbose) {
fprintf(stderr, "new anchor name, length = %u\n",
(unsigned)len);
}
}
static void
cc_append_name(const br_ssl_client_certificate_class **pctx,
const unsigned char *data, size_t len)
{
ccert_context *zc;
zc = (ccert_context *)pctx;
if (zc->verbose) {
size_t u;
for (u = 0; u < len; u ++) {
if (u == 0) {
fprintf(stderr, " ");
} else if (u > 0 && u % 16 == 0) {
fprintf(stderr, "\n ");
}
fprintf(stderr, " %02x", data[u]);
}
if (len > 0) {
fprintf(stderr, "\n");
}
}
}
static void
cc_end_name(const br_ssl_client_certificate_class **pctx)
{
(void)pctx;
}
static void
cc_end_name_list(const br_ssl_client_certificate_class **pctx)
{
ccert_context *zc;
zc = (ccert_context *)pctx;
if (zc->verbose) {
fprintf(stderr, "--- anchor DN list end ---\n");
}
}
static void
print_hashes(unsigned hh, unsigned hh2)
{
int i;
for (i = 0; i < 8; i ++) {
const char *name;
name = hash_function_name(i);
if (((hh >> i) & 1) != 0) {
fprintf(stderr, " %s", name);
} else if (((hh2 >> i) & 1) != 0) {
fprintf(stderr, " (%s)", name);
}
}
}
static int
choose_hash(unsigned hh)
{
static const int f[] = {
br_sha256_ID, br_sha224_ID, br_sha384_ID, br_sha512_ID,
br_sha1_ID, br_md5sha1_ID, -1
};
size_t u;
for (u = 0; f[u] >= 0; u ++) {
if (((hh >> f[u]) & 1) != 0) {
return f[u];
}
}
return -1;
}
static void
cc_choose(const br_ssl_client_certificate_class **pctx,
const br_ssl_client_context *cc, uint32_t auth_types,
br_ssl_client_certificate *choices)
{
ccert_context *zc;
int scurve;
zc = (ccert_context *)pctx;
scurve = br_ssl_client_get_server_curve(cc);
if (zc->verbose) {
unsigned hashes;
hashes = br_ssl_client_get_server_hashes(cc);
if ((auth_types & 0x00FF) != 0) {
fprintf(stderr, "supported: RSA signatures:");
print_hashes(auth_types, hashes);
fprintf(stderr, "\n");
}
if ((auth_types & 0xFF00) != 0) {
fprintf(stderr, "supported: ECDSA signatures:");
print_hashes(auth_types >> 8, hashes >> 8);
fprintf(stderr, "\n");
}
if ((auth_types & 0x010000) != 0) {
fprintf(stderr, "supported:"
" fixed ECDH (cert signed with RSA)\n");
}
if ((auth_types & 0x020000) != 0) {
fprintf(stderr, "supported:"
" fixed ECDH (cert signed with ECDSA)\n");
}
if (scurve) {
fprintf(stderr, "server key curve: %s (%d)\n",
ec_curve_name(scurve), scurve);
} else {
fprintf(stderr, "server key is not EC\n");
}
}
switch (zc->sk->key_type) {
case BR_KEYTYPE_RSA:
if ((choices->hash_id = choose_hash(auth_types)) >= 0) {
if (zc->verbose) {
fprintf(stderr, "using RSA, hash = %d (%s)\n",
choices->hash_id,
hash_function_name(choices->hash_id));
}
choices->auth_type = BR_AUTH_RSA;
choices->chain = zc->chain;
choices->chain_len = zc->chain_len;
return;
}
break;
case BR_KEYTYPE_EC:
if (zc->issuer_key_type != 0
&& scurve == zc->sk->key.ec.curve)
{
int x;
x = (zc->issuer_key_type == BR_KEYTYPE_RSA) ? 16 : 17;
if (((auth_types >> x) & 1) != 0) {
if (zc->verbose) {
fprintf(stderr, "using static ECDH\n");
}
choices->auth_type = BR_AUTH_ECDH;
choices->hash_id = -1;
choices->chain = zc->chain;
choices->chain_len = zc->chain_len;
return;
}
}
if ((choices->hash_id = choose_hash(auth_types >> 8)) >= 0) {
if (zc->verbose) {
fprintf(stderr, "using ECDSA, hash = %d (%s)\n",
choices->hash_id,
hash_function_name(choices->hash_id));
}
choices->auth_type = BR_AUTH_ECDSA;
choices->chain = zc->chain;
choices->chain_len = zc->chain_len;
return;
}
break;
}
if (zc->verbose) {
fprintf(stderr, "no matching client certificate\n");
}
choices->chain = NULL;
choices->chain_len = 0;
}
static uint32_t
cc_do_keyx(const br_ssl_client_certificate_class **pctx,
unsigned char *data, size_t len)
{
ccert_context *zc;
zc = (ccert_context *)pctx;
return br_ec_prime_i31.mul(data, len, zc->sk->key.ec.x,
zc->sk->key.ec.xlen, zc->sk->key.ec.curve);
}
static size_t
cc_do_sign(const br_ssl_client_certificate_class **pctx,
int hash_id, size_t hv_len, unsigned char *data, size_t len)
{
ccert_context *zc;
unsigned char hv[64];
zc = (ccert_context *)pctx;
memcpy(hv, data, hv_len);
switch (zc->sk->key_type) {
const br_hash_class *hc;
const unsigned char *hash_oid;
uint32_t x;
size_t sig_len;
case BR_KEYTYPE_RSA:
hash_oid = get_hash_oid(hash_id);
if (hash_oid == NULL && hash_id != 0) {
if (zc->verbose) {
fprintf(stderr, "ERROR: cannot RSA-sign with"
" unknown hash function: %d\n",
hash_id);
}
return 0;
}
sig_len = (zc->sk->key.rsa.n_bitlen + 7) >> 3;
if (len < sig_len) {
if (zc->verbose) {
fprintf(stderr, "ERROR: cannot RSA-sign,"
" buffer is too small"
" (sig=%lu, buf=%lu)\n",
(unsigned long)sig_len,
(unsigned long)len);
}
return 0;
}
x = br_rsa_i31_pkcs1_sign(hash_oid, hv, hv_len,
&zc->sk->key.rsa, data);
if (!x) {
if (zc->verbose) {
fprintf(stderr, "ERROR: RSA-sign failure\n");
}
return 0;
}
return sig_len;
case BR_KEYTYPE_EC:
hc = get_hash_impl(hash_id);
if (hc == NULL) {
if (zc->verbose) {
fprintf(stderr, "ERROR: cannot ECDSA-sign with"
" unknown hash function: %d\n",
hash_id);
}
return 0;
}
if (len < 139) {
if (zc->verbose) {
fprintf(stderr, "ERROR: cannot ECDSA-sign"
" (output buffer = %lu)\n",
(unsigned long)len);
}
return 0;
}
sig_len = br_ecdsa_i31_sign_asn1(&br_ec_prime_i31,
hc, hv, &zc->sk->key.ec, data);
if (sig_len == 0) {
if (zc->verbose) {
fprintf(stderr, "ERROR: ECDSA-sign failure\n");
}
return 0;
}
return sig_len;
default:
return 0;
}
}
static const br_ssl_client_certificate_class ccert_vtable = {
sizeof(ccert_context),
cc_start_name_list,
cc_start_name,
cc_append_name,
cc_end_name,
cc_end_name_list,
cc_choose,
cc_do_keyx,
cc_do_sign
};
static void
usage_client(void)
{
@ -139,6 +441,12 @@ usage_client(void)
fprintf(stderr,
" -CA file add certificates in 'file' to trust anchors\n");
fprintf(stderr,
" -cert file set client certificate chain\n");
fprintf(stderr,
" -key file set client private key (for certificate authentication)\n");
fprintf(stderr,
" -nostaticecdh prohibit full-static ECDH (client certificate)\n");
fprintf(stderr,
" -list list supported names (protocols, algorithms...)\n");
fprintf(stderr,
" -vmin name set minimum supported version (default: TLS-1.0)\n");
@ -179,6 +487,11 @@ do_client(int argc, char *argv[])
br_x509_minimal_context xc;
x509_noanchor_context xwc;
const br_hash_class *dnhash;
ccert_context zc;
br_x509_certificate *chain;
size_t chain_len;
private_key *sk;
int nostaticecdh;
unsigned char *iobuf;
size_t iobuf_len;
size_t minhello_len;
@ -200,6 +513,10 @@ do_client(int argc, char *argv[])
num_suites = 0;
hfuns = 0;
suite_ids = NULL;
chain = NULL;
chain_len = 0;
sk = NULL;
nostaticecdh = 0;
iobuf = NULL;
iobuf_len = 0;
minhello_len = (size_t)-1;
@ -279,6 +596,44 @@ do_client(int argc, char *argv[])
usage_client();
goto client_exit_error;
}
} else if (eqstr(arg, "-cert")) {
if (++ i >= argc) {
fprintf(stderr,
"ERROR: no argument for '-cert'\n");
usage_client();
goto client_exit_error;
}
if (chain != NULL) {
fprintf(stderr,
"ERROR: duplicate certificate chain\n");
usage_client();
goto client_exit_error;
}
arg = argv[i];
chain = read_certificates(arg, &chain_len);
if (chain == NULL || chain_len == 0) {
goto client_exit_error;
}
} else if (eqstr(arg, "-key")) {
if (++ i >= argc) {
fprintf(stderr,
"ERROR: no argument for '-key'\n");
usage_client();
goto client_exit_error;
}
if (sk != NULL) {
fprintf(stderr,
"ERROR: duplicate private key\n");
usage_client();
goto client_exit_error;
}
arg = argv[i];
sk = read_private_key(arg);
if (sk == NULL) {
goto client_exit_error;
}
} else if (eqstr(arg, "-nostaticecdh")) {
nostaticecdh = 1;
} else if (eqstr(arg, "-list")) {
list_names();
goto client_exit;
@ -412,7 +767,7 @@ do_client(int argc, char *argv[])
}
if (u == 0) {
host = xstrdup(server_name);
port = "443";
port = xstrdup("443");
} else {
port = xstrdup(server_name + u);
host = xmalloc(u);
@ -423,6 +778,19 @@ do_client(int argc, char *argv[])
sni = host;
}
if (chain == NULL && sk != NULL) {
fprintf(stderr, "ERROR: private key specified, but"
" no certificate chain\n");
usage_client();
goto client_exit_error;
}
if (chain != NULL && sk == NULL) {
fprintf(stderr, "ERROR: certificate chain specified, but"
" no private key\n");
usage_client();
goto client_exit_error;
}
if (vmin == 0) {
vmin = BR_TLS10;
}
@ -560,11 +928,13 @@ do_client(int argc, char *argv[])
}
if ((req & REQ_ECDHE_RSA) != 0) {
br_ssl_engine_set_ec(&cc.eng, &br_ec_prime_i31);
br_ssl_client_set_rsavrfy(&cc, &br_rsa_i31_pkcs1_vrfy);
br_ssl_engine_set_rsavrfy(&cc.eng,
&br_rsa_i31_pkcs1_vrfy);
}
if ((req & REQ_ECDHE_ECDSA) != 0) {
br_ssl_engine_set_ec(&cc.eng, &br_ec_prime_i31);
br_ssl_client_set_ecdsa(&cc, &br_ecdsa_i31_vrfy_asn1);
br_ssl_engine_set_ecdsa(&cc.eng,
&br_ecdsa_i31_vrfy_asn1);
}
if ((req & REQ_ECDH) != 0) {
br_ssl_engine_set_ec(&cc.eng, &br_ec_prime_i31);
@ -624,6 +994,23 @@ do_client(int argc, char *argv[])
}
br_ssl_engine_set_all_flags(&cc.eng, flags);
if (chain != NULL) {
zc.vtable = &ccert_vtable;
zc.verbose = verbose;
zc.chain = chain;
zc.chain_len = chain_len;
zc.sk = sk;
if (nostaticecdh || sk->key_type != BR_KEYTYPE_EC) {
zc.issuer_key_type = 0;
} else {
zc.issuer_key_type = get_cert_signer_algo(&chain[0]);
if (zc.issuer_key_type == 0) {
goto client_exit_error;
}
}
br_ssl_client_set_client_certificate(&cc, &zc.vtable);
}
br_ssl_engine_set_buffer(&cc.eng, iobuf, iobuf_len, bidi);
br_ssl_client_reset(&cc, sni, 0);
@ -657,9 +1044,12 @@ do_client(int argc, char *argv[])
*/
client_exit:
xfree(host);
xfree(port);
xfree(suites);
xfree(suite_ids);
VEC_CLEAREXT(anchors, &free_ta_contents);
free_certificates(chain, chain_len);
free_private_key(sk);
xfree(iobuf);
if (fd >= 0) {
close(fd);

View file

@ -157,7 +157,18 @@ static struct {
}, {
BR_ERR_BAD_SIGNATURE,
"BR_ERR_BAD_SIGNATURE",
"Invalid signature on ServerKeyExchange message."
"Invalid signature in ServerKeyExchange or"
" CertificateVerify message."
}, {
BR_ERR_WRONG_KEY_USAGE,
"BR_ERR_WRONG_KEY_USAGE",
"Peer's public key does not have the proper type or is"
" not allowed for the requested operation."
}, {
BR_ERR_NO_CLIENT_AUTH,
"BR_ERR_NO_CLIENT_AUTH",
"Client did not send a certificate upon request, or the"
" client certificate could not be validated."
}, {
BR_ERR_IO,
"BR_ERR_IO",

View file

@ -300,3 +300,15 @@ read_certificates(const char *fname, size_t *num)
VEC_CLEAR(cert_list);
return xcs;
}
/* see brssl.h */
void
free_certificates(br_x509_certificate *certs, size_t num)
{
size_t u;
for (u = 0; u < num; u ++) {
xfree(certs[u].data);
}
xfree(certs);
}

View file

@ -168,3 +168,64 @@ free_private_key(private_key *sk)
}
xfree(sk);
}
/*
* OID for hash functions in RSA signatures.
*/
static const unsigned char HASH_OID_SHA1[] = {
0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A
};
static const unsigned char HASH_OID_SHA224[] = {
0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04
};
static const unsigned char HASH_OID_SHA256[] = {
0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01
};
static const unsigned char HASH_OID_SHA384[] = {
0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02
};
static const unsigned char HASH_OID_SHA512[] = {
0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03
};
static const unsigned char *HASH_OID[] = {
HASH_OID_SHA1,
HASH_OID_SHA224,
HASH_OID_SHA256,
HASH_OID_SHA384,
HASH_OID_SHA512
};
/* see brssl.h */
const unsigned char *
get_hash_oid(int id)
{
if (id >= 2 && id <= 6) {
return HASH_OID[id - 2];
} else {
return NULL;
}
}
/* see brssl.h */
const br_hash_class *
get_hash_impl(int hash_id)
{
size_t u;
for (u = 0; hash_functions[u].name; u ++) {
const br_hash_class *hc;
int id;
hc = hash_functions[u].hclass;
id = (hc->desc >> BR_HASHDESC_ID_OFF) & BR_HASHDESC_ID_MASK;
if (id == hash_id) {
return hc;
}
}
return NULL;
}

View file

@ -651,3 +651,20 @@ ec_curve_name(int curve)
return "unknown";
}
}
/* see brssl.h */
const char *
hash_function_name(int id)
{
switch (id) {
case br_md5sha1_ID: return "MD5+SHA-1";
case br_md5_ID: return "MD5";
case br_sha1_ID: return "SHA-1";
case br_sha224_ID: return "SHA-224";
case br_sha256_ID: return "SHA-256";
case br_sha384_ID: return "SHA-384";
case br_sha512_ID: return "SHA-512";
default:
return "unknown";
}
}

View file

@ -214,6 +214,10 @@ usage_server(void)
fprintf(stderr,
" -key fname read private key from file 'fname'\n");
fprintf(stderr,
" -CA file add trust anchors from 'file' (for client auth)\n");
fprintf(stderr,
" -anon_ok request but do not require a client certificate\n");
fprintf(stderr,
" -list list supported names (protocols, algorithms...)\n");
fprintf(stderr,
" -vmin name set minimum supported version (default: TLS-1.0)\n");
@ -237,22 +241,45 @@ typedef struct {
private_key *sk;
} policy_context;
static int
get_cert_signer_algo(br_x509_certificate *xc)
static void
print_hashes(unsigned chashes)
{
br_x509_decoder_context dc;
int err;
int i;
br_x509_decoder_init(&dc, 0, 0);
br_x509_decoder_push(&dc, xc->data, xc->data_len);
err = br_x509_decoder_last_error(&dc);
if (err != 0) {
return -err;
} else {
return br_x509_decoder_get_signer_key_type(&dc);
for (i = 2; i <= 6; i ++) {
if ((chashes >> i) & 1) {
int z;
switch (i) {
case 3: z = 224; break;
case 4: z = 256; break;
case 5: z = 384; break;
case 6: z = 512; break;
default:
z = 1;
break;
}
fprintf(stderr, " sha%d", z);
}
}
}
static int
choose_hash(unsigned chashes)
{
int hash_id;
for (hash_id = 6; hash_id >= 2; hash_id --) {
if (((chashes >> hash_id) & 1) != 0) {
return hash_id;
}
}
/*
* Normally unreachable.
*/
return 0;
}
static int
sp_choose(const br_ssl_server_policy_class **pctx,
const br_ssl_server_context *cc,
@ -262,16 +289,10 @@ sp_choose(const br_ssl_server_policy_class **pctx,
const br_suite_translated *st;
size_t u, st_num;
unsigned chashes;
int hash_id;
pc = (policy_context *)pctx;
st = br_ssl_server_get_client_suites(cc, &st_num);
chashes = br_ssl_server_get_client_hashes(cc);
for (hash_id = 6; hash_id >= 2; hash_id --) {
if ((chashes >> hash_id) & 1) {
break;
}
}
if (pc->verbose) {
fprintf(stderr, "Client parameters:\n");
fprintf(stderr, " Maximum version: ");
@ -301,24 +322,17 @@ sp_choose(const br_ssl_server_policy_class **pctx,
get_suite_name_ext(st[u][0], csn, sizeof csn);
fprintf(stderr, " %s\n", csn);
}
fprintf(stderr, " Common hash functions:");
for (u = 2; u <= 6; u ++) {
if ((chashes >> u) & 1) {
int z;
switch (u) {
case 3: z = 224; break;
case 4: z = 256; break;
case 5: z = 384; break;
case 6: z = 512; break;
default:
z = 1;
break;
}
fprintf(stderr, " sha%d", z);
}
fprintf(stderr, " Common sign+hash functions:\n");
if ((chashes & 0xFF) != 0) {
fprintf(stderr, " with RSA:");
print_hashes(chashes);
fprintf(stderr, "\n");
}
if ((chashes >> 8) != 0) {
fprintf(stderr, " with ECDSA:");
print_hashes(chashes >> 8);
fprintf(stderr, "\n");
}
fprintf(stderr, "\n");
}
for (u = 0; u < st_num; u ++) {
unsigned tt;
@ -337,9 +351,10 @@ sp_choose(const br_ssl_server_policy_class **pctx,
if (br_ssl_engine_get_version(&cc->eng)
< BR_TLS12)
{
hash_id = 0;
choices->hash_id = 0;
} else {
choices->hash_id = choose_hash(chashes);
}
choices->hash_id = hash_id;
goto choose_ok;
}
break;
@ -349,9 +364,11 @@ sp_choose(const br_ssl_server_policy_class **pctx,
if (br_ssl_engine_get_version(&cc->eng)
< BR_TLS12)
{
hash_id = br_sha1_ID;
choices->hash_id = br_sha1_ID;
} else {
choices->hash_id =
choose_hash(chashes >> 8);
}
choices->hash_id = hash_id;
goto choose_ok;
}
break;
@ -409,55 +426,6 @@ sp_do_keyx(const br_ssl_server_policy_class **pctx,
}
}
/*
* OID for hash functions in RSA signatures.
*/
static const unsigned char HASH_OID_SHA1[] = {
0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A
};
static const unsigned char HASH_OID_SHA224[] = {
0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04
};
static const unsigned char HASH_OID_SHA256[] = {
0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01
};
static const unsigned char HASH_OID_SHA384[] = {
0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02
};
static const unsigned char HASH_OID_SHA512[] = {
0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03
};
static const unsigned char *HASH_OID[] = {
HASH_OID_SHA1,
HASH_OID_SHA224,
HASH_OID_SHA256,
HASH_OID_SHA384,
HASH_OID_SHA512
};
static const br_hash_class *
get_hash_impl(int hash_id)
{
size_t u;
for (u = 0; hash_functions[u].name; u ++) {
const br_hash_class *hc;
int id;
hc = hash_functions[u].hclass;
id = (hc->desc >> BR_HASHDESC_ID_OFF) & BR_HASHDESC_ID_MASK;
if (id == hash_id) {
return hc;
}
}
return NULL;
}
static size_t
sp_do_sign(const br_ssl_server_policy_class **pctx,
int hash_id, size_t hv_len, unsigned char *data, size_t len)
@ -474,11 +442,8 @@ sp_do_sign(const br_ssl_server_policy_class **pctx,
const br_hash_class *hc;
case BR_KEYTYPE_RSA:
if (hash_id == 0) {
hash_oid = NULL;
} else if (hash_id >= 2 && hash_id <= 6) {
hash_oid = HASH_OID[hash_id - 2];
} else {
hash_oid = get_hash_oid(hash_id);
if (hash_oid == NULL && hash_id != 0) {
if (pc->verbose) {
fprintf(stderr, "ERROR: cannot RSA-sign with"
" unknown hash function: %d\n",
@ -566,6 +531,9 @@ do_server(int argc, char *argv[])
size_t chain_len;
int cert_signer_algo;
private_key *sk;
anchor_list anchors = VEC_INIT;
br_x509_minimal_context xc;
const br_hash_class *dnhash;
size_t u;
br_ssl_server_context cc;
policy_context pc;
@ -713,6 +681,20 @@ do_server(int argc, char *argv[])
if (sk == NULL) {
goto server_exit_error;
}
} else if (eqstr(arg, "-CA")) {
if (++ i >= argc) {
fprintf(stderr,
"ERROR: no argument for '-CA'\n");
usage_server();
goto server_exit_error;
}
arg = argv[i];
if (read_trust_anchors(&anchors, arg) == 0) {
usage_server();
goto server_exit_error;
}
} else if (eqstr(arg, "-anon_ok")) {
flags |= BR_OPT_TOLERATE_NO_CLIENT_AUTH;
} else if (eqstr(arg, "-list")) {
list_names();
goto server_exit;
@ -872,11 +854,10 @@ do_server(int argc, char *argv[])
break;
}
cert_signer_algo = get_cert_signer_algo(chain);
if (cert_signer_algo < 0) {
fprintf(stderr, "ERROR: server certificate cannot be"
" decoded (err=%d)\n", -cert_signer_algo);
if (cert_signer_algo == 0) {
goto server_exit_error;
} else if (verbose) {
}
if (verbose) {
const char *csas;
switch (cert_signer_algo) {
@ -980,6 +961,7 @@ do_server(int argc, char *argv[])
}
br_ssl_engine_set_suites(&cc.eng, suite_ids, num_suites);
dnhash = NULL;
for (u = 0; hash_functions[u].name; u ++) {
const br_hash_class *hc;
int id;
@ -987,6 +969,7 @@ do_server(int argc, char *argv[])
hc = hash_functions[u].hclass;
id = (hc->desc >> BR_HASHDESC_ID_OFF) & BR_HASHDESC_ID_MASK;
if ((hfuns & ((unsigned)1 << id)) != 0) {
dnhash = hc;
br_ssl_engine_set_hash(&cc.eng, id, hc);
}
}
@ -1007,6 +990,11 @@ do_server(int argc, char *argv[])
br_ssl_session_cache_lru_init(&lru, cache, cache_len);
br_ssl_server_set_cache(&cc, &lru.vtable);
/*
* Set the policy handler (that chooses the actual cipher suite,
* selects the certificate chain, and runs the private key
* operations).
*/
pc.vtable = &policy_vtable;
pc.verbose = verbose;
pc.chain = chain;
@ -1015,6 +1003,36 @@ do_server(int argc, char *argv[])
pc.sk = sk;
br_ssl_server_set_policy(&cc, &pc.vtable);
/*
* If trust anchors have been configured, then set an X.509
* validation engine and activate client certificate
* authentication.
*/
if (VEC_LEN(anchors) != 0) {
br_x509_minimal_init(&xc, dnhash,
&VEC_ELT(anchors, 0), VEC_LEN(anchors));
for (u = 0; hash_functions[u].name; u ++) {
const br_hash_class *hc;
int id;
hc = hash_functions[u].hclass;
id = (hc->desc >> BR_HASHDESC_ID_OFF)
& BR_HASHDESC_ID_MASK;
if ((hfuns & ((unsigned)1 << id)) != 0) {
br_x509_minimal_set_hash(&xc, id, hc);
}
}
br_ssl_engine_set_rsavrfy(&cc.eng, &br_rsa_i31_pkcs1_vrfy);
br_ssl_engine_set_ec(&cc.eng, &br_ec_prime_i31);
br_ssl_engine_set_ecdsa(&cc.eng, &br_ecdsa_i31_vrfy_asn1);
br_x509_minimal_set_rsa(&xc, &br_rsa_i31_pkcs1_vrfy);
br_x509_minimal_set_ecdsa(&xc,
&br_ec_prime_i31, &br_ecdsa_i31_vrfy_asn1);
br_ssl_engine_set_x509(&cc.eng, &xc.vtable);
br_ssl_server_set_trust_anchor_names_alt(&cc,
&VEC_ELT(anchors, 0), VEC_LEN(anchors));
}
br_ssl_engine_set_buffer(&cc.eng, iobuf, iobuf_len, bidi);
/*
@ -1061,13 +1079,9 @@ do_server(int argc, char *argv[])
server_exit:
xfree(suites);
xfree(suite_ids);
if (chain != NULL) {
for (u = 0; u < chain_len; u ++) {
xfree(chain[u].data);
}
xfree(chain);
}
free_certificates(chain, chain_len);
free_private_key(sk);
VEC_CLEAREXT(anchors, &free_ta_contents);
xfree(iobuf);
xfree(cache);
if (fd >= 0) {

View file

@ -93,7 +93,7 @@ print_ta_internals(br_x509_trust_anchor *ta, long ctr)
char tmp[25];
sprintf(tmp, "TA%ld_DN", ctr);
print_blob(tmp, ta->dn, ta->dn_len);
print_blob(tmp, ta->dn.data, ta->dn.len);
switch (ta->pkey.key_type) {
case BR_KEYTYPE_RSA:
sprintf(tmp, "TA%ld_RSA_N", ctr);
@ -119,7 +119,8 @@ print_ta(br_x509_trust_anchor *ta, long ctr)
char tmp[25];
printf("\t{\n");
printf("\t\t(unsigned char *)TA%ld_DN, sizeof TA%ld_DN,\n", ctr, ctr);
printf("\t\t{ (unsigned char *)TA%ld_DN, sizeof TA%ld_DN },\n",
ctr, ctr);
printf("\t\t%s,\n", (ta->flags & BR_X509_TA_CA)
? "BR_X509_TA_CA" : "0");
printf("\t\t{\n");

View file

@ -181,9 +181,11 @@ do_verify(int argc, char *argv[])
cert_list chain = VEC_INIT;
size_t u;
br_x509_minimal_context mc;
int err_keyx, err_sign;
int err;
int print_text, print_C;
br_x509_pkey *pk;
const br_x509_pkey *tpk;
unsigned usages;
retcode = 0;
verbose = 1;
@ -191,8 +193,6 @@ do_verify(int argc, char *argv[])
print_text = 0;
print_C = 0;
pk = NULL;
err_keyx = 0;
err_sign = 0;
for (i = 0; i < argc; i ++) {
const char *arg;
@ -266,55 +266,44 @@ do_verify(int argc, char *argv[])
br_x509_minimal_set_rsa(&mc, &br_rsa_i31_pkcs1_vrfy);
br_x509_minimal_set_ecdsa(&mc,
&br_ec_prime_i31, &br_ecdsa_i31_vrfy_asn1);
for (i = 0; i < 2; i ++) {
const br_x509_pkey *tpk;
int err;
mc.vtable->start_chain(&mc.vtable,
i == 0 ? BR_KEYTYPE_KEYX : BR_KEYTYPE_SIGN, sni);
for (u = 0; u < VEC_LEN(chain); u ++) {
br_x509_certificate *xc;
mc.vtable->start_chain(&mc.vtable, sni);
for (u = 0; u < VEC_LEN(chain); u ++) {
br_x509_certificate *xc;
xc = &VEC_ELT(chain, u);
mc.vtable->start_cert(&mc.vtable, xc->data_len);
mc.vtable->append(&mc.vtable, xc->data, xc->data_len);
mc.vtable->end_cert(&mc.vtable);
}
err = mc.vtable->end_chain(&mc.vtable);
if (i == 0) {
err_keyx = err;
} else {
err_sign = err;
}
tpk = mc.vtable->get_pkey(&mc.vtable);
if (pk == NULL && tpk != NULL) {
pk = xpkeydup(tpk);
}
xc = &VEC_ELT(chain, u);
mc.vtable->start_cert(&mc.vtable, xc->data_len);
mc.vtable->append(&mc.vtable, xc->data, xc->data_len);
mc.vtable->end_cert(&mc.vtable);
}
if (err_keyx == 0 || err_sign == 0) {
err = mc.vtable->end_chain(&mc.vtable);
tpk = mc.vtable->get_pkey(&mc.vtable, &usages);
if (tpk != NULL) {
pk = xpkeydup(tpk);
}
if (err == 0) {
if (verbose) {
fprintf(stderr, "Validation success");
if (err_keyx == 0 && err_sign == 0) {
fprintf(stderr, " (key exchange, sign)\n");
} else if (err_keyx == 0) {
fprintf(stderr, " (key exchange)\n");
} else if (err_sign == 0) {
fprintf(stderr, " (signature)\n");
int hkx;
fprintf(stderr, "Validation success; usages:");
hkx = 0;
if (usages & BR_KEYTYPE_KEYX) {
fprintf(stderr, " key exchange");
hkx = 1;
}
if (usages & BR_KEYTYPE_SIGN) {
if (hkx) {
fprintf(stderr, ",");
}
fprintf(stderr, " signature");
}
fprintf(stderr, "\n");
}
} else {
if (verbose) {
int err;
const char *errname, *errmsg;
/*
* If the two error codes differ, we want the one
* which is not a "forbidden key usage".
*/
err = err_keyx;
if (err == BR_ERR_X509_FORBIDDEN_KEY_USAGE) {
err = err_sign;
}
fprintf(stderr, "Validation failed, err = %d", err);
errname = find_error_name(err, &errmsg);
if (errname != NULL) {