diff options
author | Francis Dupont <fdupont@isc.org> | 2015-06-05 18:26:18 +0200 |
---|---|---|
committer | Francis Dupont <fdupont@isc.org> | 2015-06-05 18:26:18 +0200 |
commit | 1e1561b5ef5089b7b8460383d9f8718de0f09c42 (patch) | |
tree | d6d1afaedd3c40708878551662c251ec07668beb | |
parent | 8c4734c44b993983eb627d4e32d5dfe751eed7d6 (diff) | |
download | isc-dhcp-1e1561b5ef5089b7b8460383d9f8718de0f09c42.tar.gz |
moved to native OpenSSLsecure_client
-rw-r--r-- | client/dhc6.c | 182 | ||||
-rw-r--r-- | client/dhclient.8 | 14 | ||||
-rw-r--r-- | client/dhclient.c | 71 | ||||
-rw-r--r-- | includes/dhcpd.h | 2 | ||||
-rw-r--r-- | util/Makefile.bind.in | 3 |
5 files changed, 163 insertions, 109 deletions
diff --git a/client/dhc6.c b/client/dhc6.c index 06a1a5ad..4a55f4fe 100644 --- a/client/dhc6.c +++ b/client/dhc6.c @@ -5239,14 +5239,12 @@ secure_dhc6_add(struct data_string *packet) struct data_string tbs; struct data_string tmstmp; struct data_string sign; + EVP_MD_CTX ctx; + EVP_PKEY *pkey = (EVP_PKEY *) key; isc_uint64_t sec; isc_uint64_t fraction; - dst_context_t *ctx = NULL; - isc_region_t r; - isc_buffer_t sigbuf; - unsigned int siglen = 0; - int savedlen = (int) packet->len; - isc_result_t result; + int siglen, savedlen = (int) packet->len; + unsigned size; /* Prepare a to be signed copy of the packet */ memset(&tbs, 0, sizeof(tbs)); @@ -5295,22 +5293,23 @@ secure_dhc6_add(struct data_string *packet) } /* Prepare the signature option */ - result = dst_key_sigsize(key, &siglen); - if (result != ISC_R_SUCCESS) { - log_error("dst_key_sigsize: %s.", isc_result_totext(result)); + siglen = EVP_PKEY_size(pkey); + if (siglen <= 0) { + log_error("EVP_PKEY_size failed"); data_string_forget(&tbs, MDL); data_string_forget(&tmstmp, MDL); return; } - if (!buffer_allocate(&sign.buffer, siglen, MDL)) { + size = (unsigned) siglen; + if (!buffer_allocate(&sign.buffer, size, MDL)) { log_error("Unable to allocate memory for signature."); data_string_forget(&tbs, MDL); data_string_forget(&tmstmp, MDL); return; } - memset(sign.buffer->data, 0, siglen + 2); + memset(sign.buffer->data, 0, size + 2); sign.data = sign.buffer->data; - sign.len = siglen + 2; + sign.len = size + 2; /* TODO: map algos */ sign.buffer->data[0] = SHA_256; sign.buffer->data[1] = RSASSA_PKCS1v1_5; @@ -5323,43 +5322,32 @@ secure_dhc6_add(struct data_string *packet) return; } - /* Get a signing context */ - result = dst_context_create(key, dhcp_gbl_ctx.mctx, &ctx); - if (result != ISC_R_SUCCESS) { - log_error("dst_context_create: %s.", - isc_result_totext(result)); + /* Sign */ + EVP_MD_CTX_init(&ctx); + if (!EVP_DigestInit_ex(&ctx, EVP_sha256(), NULL)) { + log_error("EVP_DigestInit_ex failed"); data_string_forget(&tbs, MDL); data_string_forget(&tmstmp, MDL); data_string_forget(&sign, MDL); return; } - - /* Digest the to be signed copy */ - r.base = tbs.buffer->data; - r.length = tbs.len; - result = dst_context_adddata(ctx, &r); - if (result != ISC_R_SUCCESS) { - log_error("dst_context_adddata: %s.", - isc_result_totext(result)); + if (!EVP_DigestUpdate(&ctx, tbs.data, tbs.len)) { + log_error("EVP_DigestUpdate failed"); data_string_forget(&tbs, MDL); data_string_forget(&tmstmp, MDL); data_string_forget(&sign, MDL); - dst_context_destroy(&ctx); return; } - - /* Sign */ - isc_buffer_init(&sigbuf, &sign.buffer->data[2], siglen); - result = dst_context_sign(ctx, &sigbuf); - data_string_forget(&tbs, MDL); - dst_context_destroy(&ctx); - if (result != ISC_R_SUCCESS) { - log_error("dst_context_sign: %s.", - isc_result_totext(result)); + if (!EVP_SignFinal(&ctx, sign.buffer->data + 2, &size, pkey)) { + log_error("EVP_SignFinal failed"); + data_string_forget(&tbs, MDL); data_string_forget(&tmstmp, MDL); data_string_forget(&sign, MDL); + EVP_MD_CTX_cleanup(&ctx); return; } + data_string_forget(&tbs, MDL); + EVP_MD_CTX_cleanup(&ctx); /* Push the public key/certificate option on the packet */ if (!append_option(packet, &dhcpv6_universe, @@ -5632,4 +5620,128 @@ valid_secure_dhc6(struct packet *packet) log_info("signature is valid."); return ISC_TRUE; } + +#define DER_MAXSIZE 16*1024 + +void +get_keys(const char *rootname) +{ + + char *tmp; + FILE *fp = NULL; + EVP_PKEY *pkey = (EVP_PKEY *) key; + EVP_PKEY *pubkey; + RSA *rsa; + X509 *x509; + size_t nlen = strlen(rootname); + isc_result_t ret; + int len, nid; + unsigned char *p; + + nlen += 20; + tmp = dmalloc(nlen, MDL); + if (!tmp) + log_fatal("No memory for %s", rootname); + + /* Get the private key - PKCS#1 or PKCS#8 format. */ + (void) snprintf(tmp, nlen, "%s.pkcs8", rootname); + ret = isc_stdio_open(tmp, "r", &fp); + if (ret != ISC_R_SUCCESS) { + (void) snprintf(tmp, nlen, "%s.priv", rootname); + ret = isc_stdio_open(tmp, "r", &fp); + } + if (ret != ISC_R_SUCCESS) + log_fatal("can't open '%s': %s", tmp, isc_result_totext(ret)); + pkey = PEM_read_PrivateKey(fp, NULL, 0, NULL); + fclose(fp); + if (!pkey) + log_fatal("PEM_read_PrivateKey() failed"); + key = (void *) pkey; + + /* Get the public key - PKCS#1 format. */ + (void) snprintf(tmp, nlen, "%s.pub", rootname); + ret = isc_stdio_open(tmp, "r", &fp); + if (ret != ISC_R_SUCCESS) + goto spki; + rsa = PEM_read_RSAPublicKey(fp, NULL, 0, NULL); + fclose(fp); + if (!rsa) + log_fatal("PEM_read_RSAPublicKey failed"); + goto der; + + spki: + /* Get the public key - SPKI format. */ + (void) snprintf(tmp, nlen, "%s.spki", rootname); + ret = isc_stdio_open(tmp, "r", &fp); + if (ret != ISC_R_SUCCESS) + goto cert; + pubkey = PEM_read_PUBKEY(fp, NULL, 0, NULL); + fclose(fp); + if (!pubkey) + log_fatal("PEM_read_PUBKEY failed"); + rsa = EVP_PKEY_get1_RSA(pubkey); + if (!rsa) + log_fatal("EVP_PKEY_get1_RSA failed"); + EVP_PKEY_free(pubkey); + + der: + /* Put the public key in SPKI DER format in the der data string. */ + len = i2d_RSA_PUBKEY(rsa, NULL); + if (len < 0) + log_fatal("i2d_RSA_PUBKEY failed0"); + if (len > DER_MAXSIZE) + log_fatal("the public key is too large (size %d)", len); + if (!buffer_allocate(&der.buffer, (unsigned)len, MDL)) + log_fatal("No memory for the public key in DER (size %u)", + (unsigned)len); + der.data = der.buffer->data; + der.len = (unsigned)len; + p = der.buffer->data; + len = i2d_RSA_PUBKEY(rsa, &p); + if (len != (int)der.len) + log_fatal("i2d_RSA_PUBKEY failed"); + RSA_free(rsa); + dfree(tmp, MDL); + return; + + cert: + /* Get the X.509 public key certificate. */ + is_secure = 2; + (void) snprintf(tmp, nlen, "%s.x509", rootname); + ret = isc_stdio_open(tmp, "r", &fp); + if (ret != ISC_R_SUCCESS) { + (void) snprintf(tmp, nlen, "%s.cert", rootname); + ret = isc_stdio_open(tmp, "r", &fp); + } + if (ret != ISC_R_SUCCESS) + log_fatal("can't open '%s': %s", tmp, isc_result_totext(ret)); + x509 = PEM_read_X509(fp, NULL, 0, NULL); + fclose(fp); + if (!x509) + log_fatal("PEM_read_X509 failed"); + /* Verify it is RSASHA256. */ + nid = OBJ_obj2nid(x509->sig_alg->algorithm); + /* SHA-512 is .13 */ + if (nid != OBJ_txt2nid("1.2.840.113549.1.1.11")) + log_fatal("The certificate is not for RSASHA256"); + + /* Put the certificate in DER format in the der data string. */ + len = i2d_X509(x509, NULL); + if (len < 0) + log_fatal("i2d_X509 failed0"); + if (len > DER_MAXSIZE) + log_fatal("the certificate is too large (size %d)", len); + if (!buffer_allocate(&der.buffer, (unsigned)len, MDL)) + log_fatal("No memory for the certificate in DER (size %u)", + (unsigned)len); + der.data = der.buffer->data; + der.len = (unsigned)len; + p = der.buffer->data; + len = i2d_X509(x509, &p); + if (len != (int)der.len) + log_fatal("i2d_X509 failed"); + X509_free(x509); + dfree(tmp, MDL); + return; +} #endif /* DHCPv6 */ diff --git a/client/dhclient.8 b/client/dhclient.8 index 91fd790e..239b4398 100644 --- a/client/dhclient.8 +++ b/client/dhclient.8 @@ -349,13 +349,13 @@ Use the standard DDNS scheme from RFCs 4701 & 4702. .TP .TP .BI \-k \ keys-rootname -Specify the rootname of key files for secure DHCPv6 (so requires \fB-6\fR). -The public key must be in \fIrootname.key\fR, the private key in -\fIrootname.private\fR, both in DNSSEC format for RSASHA256 or -RSASHA512. The third file is used for the public key or the certificate -secure DHCPv6 option, must be in DER format and the name is -\fIrootname.pubkeyder\fR for a public key (SubjectPublicKeyInfo) and -\fIrootname.certder\fR for a certificate (X.509 public key certificate). +Specify the rootname of PEM key files for secure DHCPv6 (so requires \fB-6\fR). +Suffixes are \fI.pkcs8\fR or \fI.priv\fR for the mandatory private key +in PKCS#8 or PKCS#1 format, \fI.spki\fR for the public key in +SubjectPublicKeyInfo (SPKI) format or \fI.pub\fR inPKCS#1 format, +or \fI.x509\fR or \fI.cert\fR for the X.509 public key certificate. +The public key or certificate file is used to build the corresponding +(and mandatory) secure DHCPv6 option. .TP .BI \--version Print version number and exit. diff --git a/client/dhclient.c b/client/dhclient.c index 488bcfb2..a5e00947 100644 --- a/client/dhclient.c +++ b/client/dhclient.c @@ -91,9 +91,9 @@ int wanted_ia_pd = 0; char *mockup_relay = NULL; int is_secure = 0; -dst_key_t *key = NULL; +void *key = NULL; struct data_string der; -const char *path_keys = NULL; +const char *keys_root_name = NULL; char *progname = NULL; @@ -109,7 +109,7 @@ static int check_domain_name_list(const char *ptr, size_t len, int dots); static int check_option_values(struct universe *universe, unsigned int opt, const char *ptr, size_t len); #ifdef DHCPv6 -static void get_der(const char *filename); +extern void get_keys(const char *rootname); #endif #ifndef UNIT_TEST @@ -323,7 +323,7 @@ main(int argc, char **argv) { local_family_set = 1; local_family = AF_INET6; is_secure = 1; - path_keys = argv[i]; + keys_root_name = argv[i]; #endif /* DHCPv6 */ } else if (!strcmp(argv[i], "-D")) { duid_v4 = 1; @@ -410,20 +410,8 @@ main(int argc, char **argv) { #ifdef DHCPv6 else if (local_family == AF_INET6) { dhcpv6_client_assignments(); - if (is_secure) { - status = dst_key_fromnamedfile(path_keys, - NULL, - DST_TYPE_PRIVATE, - dhcp_gbl_ctx.mctx, - &key); - if (status != ISC_R_SUCCESS) - log_fatal("dst_key_fromnamedfile: " - "'%s.private': %s", - path_keys, - isc_result_totext(status)); - /* TODO: check key_alg */ - get_der(path_keys); - } + if (is_secure) + get_keys(keys_root_name); } #endif /* DHCPv6 */ else @@ -793,7 +781,7 @@ static void usage() log_fatal("Usage: %s " #ifdef DHCPv6 "[-4|-6] [-SNTPI1dvrxi] [-nw] [-p <port>] [-D LL|LLT] \n" - " [-k keys-rootname]\n" + " [-k <keys-rootname>]\n" #else /* DHCPv6 */ "[-I1dvrxi] [-nw] [-p <port>] [-D LL|LLT] \n" #endif /* DHCPv6 */ @@ -4629,48 +4617,3 @@ add_reject(struct packet *packet) { */ log_info("Server added to list of rejected servers."); } - -#ifdef DHCPv6 - -#define DER_MAXSIZE 16*1024U - -static void -get_der(const char *filename) -{ - size_t len = strlen(filename); - char *tmp; - FILE *fp = NULL; - isc_result_t ret; - off_t size = 0; - - len += 20; - tmp = dmalloc(len, MDL); - if (!tmp) - log_fatal("No memory for %s", filename); - (void) snprintf(tmp, len, "%s.pubkeyder", filename); - ret = isc_stdio_open(tmp, "r", &fp); - if (ret != ISC_R_SUCCESS) { - is_secure = 2; - (void) snprintf(tmp, len, "%s.certder", filename); - ret = isc_stdio_open(tmp, "r", &fp); - } - if (ret != ISC_R_SUCCESS) - log_fatal("can't open '%s': %s", tmp, isc_result_totext(ret)); - /* isc_file_getsize() is not available in bind9.9 */ - ret = isc_file_getsizefd(fileno(fp), &size); - if (ret != ISC_R_SUCCESS) - log_fatal("can't get the size of '%s': %s", - tmp, isc_result_totext(ret)); - if (size > DER_MAXSIZE) - log_fatal("%s is too large (%u > %u)", - tmp, (unsigned)size, DER_MAXSIZE); - if (!buffer_allocate(&der.buffer, (unsigned)size, MDL)) - log_fatal("No memory for %s (size %u)", tmp, (unsigned)size); - der.data = der.buffer->data; - der.len = size; - ret = isc_stdio_read(der.buffer->data, 1, size, fp, NULL); - (void) isc_stdio_close(fp); - if (ret != ISC_R_SUCCESS) - log_fatal("can't read '%s': %s", tmp, isc_result_totext(ret)); -} -#endif /* DHCPv6 */ diff --git a/includes/dhcpd.h b/includes/dhcpd.h index 7183f32d..300353a6 100644 --- a/includes/dhcpd.h +++ b/includes/dhcpd.h @@ -2805,7 +2805,7 @@ extern struct client_config top_level_config; extern int is_secure; -extern dst_key_t *key; +extern void *key; extern struct data_string der; void dhcpoffer (struct packet *); diff --git a/util/Makefile.bind.in b/util/Makefile.bind.in index 6fe780f8..bd784c60 100644 --- a/util/Makefile.bind.in +++ b/util/Makefile.bind.in @@ -27,8 +27,7 @@ include ./bindvar.tmp bindsrcdir=bind-${version} bindconfig = --disable-kqueue --disable-epoll --disable-devpoll \ - --with-openssl=/usr/local/opt/openssl \ - --without-libxml2 --enable-exportlib \ + --without-openssl --without-libxml2 --enable-exportlib \ --with-gssapi=no --enable-threads=no @BINDCONFIG@ \ --with-export-includedir=${binddir}/include \ --with-export-libdir=${binddir}/lib |