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:
parent
e9ce2f4e8c
commit
e61ad42191
27 changed files with 4441 additions and 1482 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
396
tools/client.c
396
tools/client.c
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
61
tools/keys.c
61
tools/keys.c
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
218
tools/server.c
218
tools/server.c
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue