From cfebc30f763422c6c3466ee62251f9fa5ca22f61 Mon Sep 17 00:00:00 2001 From: Klas Lindfors Date: Thu, 2 Oct 2014 13:00:25 +0200 Subject: [PATCH] refactor to let request-cert and selfsign-cert use different hashes namely sha1 and sha512 as well with sha256 as default --- tool/yubico-piv-tool.c | 173 +++++++++++++++++++++++++++++++++++------ 1 file changed, 148 insertions(+), 25 deletions(-) diff --git a/tool/yubico-piv-tool.c b/tool/yubico-piv-tool.c index bbae054..d6f2c1e 100644 --- a/tool/yubico-piv-tool.c +++ b/tool/yubico-piv-tool.c @@ -59,11 +59,20 @@ unsigned const char chuid_tmpl[] = { }; #define CHUID_GUID_OFFS 28 +unsigned const char sha1oid[] = { + 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00, + 0x04, 0x14 +}; + unsigned const char sha256oid[] = { 0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20 }; -#define DIGEST_LEN 32 + +unsigned const char sha512oid[] = { + 0x30, 0x51, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, + 0x02, 0x03, 0x05, 0x00, 0x04, 0x40 +}; #define KEY_LEN 24 @@ -473,20 +482,25 @@ static bool set_chuid(ykpiv_state *state, int verbose) { } static bool request_certificate(ykpiv_state *state, enum enum_key_format key_format, - const char *input_file_name, const char *slot, char *subject, + const char *input_file_name, const char *slot, char *subject, enum enum_hash hash, const char *output_file_name) { X509_REQ *req = NULL; X509_NAME *name = NULL; FILE *input_file = NULL; FILE *output_file = NULL; EVP_PKEY *public_key = NULL; + const EVP_MD *md; bool ret = false; - unsigned char digest[DIGEST_LEN + sizeof(sha256oid)]; - unsigned int digest_len = DIGEST_LEN; + unsigned char digest[EVP_MAX_MD_SIZE + sizeof(sha512oid)]; // maximum.. + unsigned int digest_len; + unsigned int md_len; unsigned char algorithm; int key = 0; unsigned char *signinput; size_t len = 0; + size_t oid_len; + const unsigned char *oid; + int nid; sscanf(slot, "%x", &key); @@ -511,6 +525,30 @@ static bool request_certificate(ykpiv_state *state, enum enum_key_format key_for goto request_out; } + switch(hash) { + case hash_arg_SHA1: + md = EVP_sha1(); + oid = sha1oid; + oid_len = sizeof(sha1oid); + break; + case hash_arg_SHA256: + md = EVP_sha256(); + oid = sha256oid; + oid_len = sizeof(sha256oid); + break; + case hash_arg_SHA512: + md = EVP_sha512(); + oid = sha512oid; + oid_len = sizeof(sha512oid); + break; + case hash__NULL: + default: + goto request_out; + } + + md_len = (unsigned int)EVP_MD_block_size(md); + digest_len = sizeof(digest) - md_len; + req = X509_REQ_new(); if(!req) { fprintf(stderr, "Failed to allocate request structure.\n"); @@ -534,10 +572,10 @@ static bool request_certificate(ykpiv_state *state, enum enum_key_format key_for } memset(digest, 0, sizeof(digest)); - memcpy(digest, sha256oid, sizeof(sha256oid)); + memcpy(digest, oid, oid_len); /* XXX: this should probably use X509_REQ_digest() but that's buggy */ - if(!ASN1_item_digest(ASN1_ITEM_rptr(X509_REQ_INFO), EVP_sha256(), req->req_info, - digest + sizeof(sha256oid), &digest_len)) { + if(!ASN1_item_digest(ASN1_ITEM_rptr(X509_REQ_INFO), md, req->req_info, + digest + oid_len, &digest_len)) { fprintf(stderr, "Failed doing digest of request.\n"); goto request_out; } @@ -546,18 +584,45 @@ static bool request_certificate(ykpiv_state *state, enum enum_key_format key_for case YKPIV_ALGO_RSA1024: case YKPIV_ALGO_RSA2048: signinput = digest; - len = sizeof(digest); - req->sig_alg->algorithm = OBJ_nid2obj(NID_sha256WithRSAEncryption); + len = oid_len + digest_len; + switch(hash) { + case hash_arg_SHA1: + nid = NID_sha1WithRSAEncryption; + break; + case hash_arg_SHA256: + nid = NID_sha256WithRSAEncryption; + break; + case hash_arg_SHA512: + nid = NID_sha512WithRSAEncryption; + break; + case hash__NULL: + default: + goto request_out; + } break; case YKPIV_ALGO_ECCP256: - signinput = digest + sizeof(sha256oid); - len = DIGEST_LEN; - req->sig_alg->algorithm = OBJ_nid2obj(NID_ecdsa_with_SHA256); + signinput = digest + oid_len; + len = digest_len; + switch(hash) { + case hash_arg_SHA1: + nid = NID_ecdsa_with_SHA1; + break; + case hash_arg_SHA256: + nid = NID_ecdsa_with_SHA256; + break; + case hash_arg_SHA512: + nid = NID_ecdsa_with_SHA512; + break; + case hash__NULL: + default: + goto request_out; + } break; default: fprintf(stderr, "Unsupported algorithm %x.\n", algorithm); goto request_out; } + req->sig_alg->algorithm = OBJ_nid2obj(nid); { unsigned char signature[1024]; size_t sig_len = sizeof(signature); @@ -595,7 +660,7 @@ request_out: } static bool selfsign_certificate(ykpiv_state *state, enum enum_key_format key_format, - const char *input_file_name, const char *slot, char *subject, + const char *input_file_name, const char *slot, char *subject, enum enum_hash hash, const char *output_file_name) { FILE *input_file = NULL; FILE *output_file = NULL; @@ -603,12 +668,17 @@ static bool selfsign_certificate(ykpiv_state *state, enum enum_key_format key_fo EVP_PKEY *public_key = NULL; X509 *x509 = NULL; X509_NAME *name = NULL; - unsigned char digest[DIGEST_LEN + sizeof(sha256oid)]; - unsigned int digest_len = DIGEST_LEN; + const EVP_MD *md; + unsigned char digest[EVP_MAX_MD_SIZE + sizeof(sha512oid)]; + unsigned int digest_len; unsigned char algorithm; int key = 0; unsigned char *signinput; size_t len = 0; + size_t oid_len; + const unsigned char *oid; + int nid; + unsigned int md_len; sscanf(slot, "%x", &key); @@ -633,6 +703,30 @@ static bool selfsign_certificate(ykpiv_state *state, enum enum_key_format key_fo goto selfsign_out; } + switch(hash) { + case hash_arg_SHA1: + md = EVP_sha1(); + oid = sha1oid; + oid_len = sizeof(sha1oid); + break; + case hash_arg_SHA256: + md = EVP_sha256(); + oid = sha256oid; + oid_len = sizeof(sha256oid); + break; + case hash_arg_SHA512: + md = EVP_sha512(); + oid = sha512oid; + oid_len = sizeof(sha512oid); + break; + case hash__NULL: + default: + goto selfsign_out; + } + + md_len = (unsigned int)EVP_MD_block_size(md); + digest_len = sizeof(digest) - md_len; + x509 = X509_new(); if(!x509) { fprintf(stderr, "Failed to allocate certificate structure.\n"); @@ -675,24 +769,51 @@ static bool selfsign_certificate(ykpiv_state *state, enum enum_key_format key_fo case YKPIV_ALGO_RSA1024: case YKPIV_ALGO_RSA2048: signinput = digest; - len = sizeof(digest); - x509->sig_alg->algorithm = OBJ_nid2obj(NID_sha256WithRSAEncryption); + len = oid_len + md_len; + switch(hash) { + case hash_arg_SHA1: + nid = NID_sha1WithRSAEncryption; + break; + case hash_arg_SHA256: + nid = NID_sha256WithRSAEncryption; + break; + case hash_arg_SHA512: + nid = NID_sha512WithRSAEncryption; + break; + case hash__NULL: + default: + goto selfsign_out; + } break; case YKPIV_ALGO_ECCP256: - signinput = digest + sizeof(sha256oid); - len = DIGEST_LEN; - x509->sig_alg->algorithm = OBJ_nid2obj(NID_ecdsa_with_SHA256); + signinput = digest + oid_len; + len = md_len; + switch(hash) { + case hash_arg_SHA1: + nid = NID_ecdsa_with_SHA1; + break; + case hash_arg_SHA256: + nid = NID_ecdsa_with_SHA256; + break; + case hash_arg_SHA512: + nid = NID_ecdsa_with_SHA512; + break; + case hash__NULL: + default: + goto selfsign_out; + } break; default: fprintf(stderr, "Unsupported algorithm %x.\n", algorithm); goto selfsign_out; } + x509->sig_alg->algorithm = OBJ_nid2obj(nid); x509->cert_info->signature->algorithm = x509->sig_alg->algorithm; memset(digest, 0, sizeof(digest)); - memcpy(digest, sha256oid, sizeof(sha256oid)); + memcpy(digest, oid, oid_len); /* XXX: this should probably use X509_digest() but that looks buggy */ - if(!ASN1_item_digest(ASN1_ITEM_rptr(X509_CINF), EVP_sha256(), x509->cert_info, - digest + sizeof(sha256oid), &digest_len)) { + if(!ASN1_item_digest(ASN1_ITEM_rptr(X509_CINF), md, x509->cert_info, + digest + oid_len, &digest_len)) { fprintf(stderr, "Failed doing digest of certificate.\n"); goto selfsign_out; } @@ -1118,7 +1239,8 @@ int main(int argc, char *argv[]) { ret = EXIT_FAILURE; } else { if(request_certificate(state, args_info.key_format_arg, args_info.input_arg, - args_info.slot_orig, args_info.subject_arg, args_info.output_arg) == false) { + args_info.slot_orig, args_info.subject_arg, args_info.hash_arg, + args_info.output_arg) == false) { ret = EXIT_FAILURE; } } @@ -1165,7 +1287,8 @@ int main(int argc, char *argv[]) { ret = EXIT_FAILURE; } else { if(selfsign_certificate(state, args_info.key_format_arg, args_info.input_arg, - args_info.slot_orig, args_info.subject_arg, args_info.output_arg) == false) { + args_info.slot_orig, args_info.subject_arg, args_info.hash_arg, + args_info.output_arg) == false) { ret = EXIT_FAILURE; } }