Merge branch 'pki-addrblock'

Add support to the x509 plugin and pki to generate certificates with the
RFC 3779 addrblock extension.
This commit is contained in:
Martin Willi
2017-02-27 09:37:51 +01:00
9 changed files with 218 additions and 4 deletions
+1
View File
@@ -45,6 +45,7 @@ ENUM(builder_part_names, BUILD_FROM_FILE, BUILD_END,
"BUILD_CRL_DISTRIBUTION_POINTS",
"BUILD_OCSP_ACCESS_LOCATIONS",
"BUILD_PATHLEN",
"BUILD_ADDRBLOCKS",
"BUILD_PERMITTED_NAME_CONSTRAINTS",
"BUILD_EXCLUDED_NAME_CONSTRAINTS",
"BUILD_CERTIFICATE_POLICIES",
+2
View File
@@ -100,6 +100,8 @@ enum builder_part_t {
BUILD_OCSP_ACCESS_LOCATIONS,
/** certificate path length constraint */
BUILD_PATHLEN,
/** RFC3779 addressBlock, linked_list_t* of traffic_selector_t* */
BUILD_ADDRBLOCKS,
/** permitted X509 name constraints, linked_list_t* of identification_t* */
BUILD_PERMITTED_NAME_CONSTRAINTS,
/** excluded X509 name constraints, linked_list_t* of identification_t* */
+133 -3
View File
@@ -1992,6 +1992,72 @@ chunk_t x509_build_crlDistributionPoints(linked_list_t *list, int extn)
asn1_wrap(ASN1_SEQUENCE, "m", crlDistributionPoints)));
}
static chunk_t generate_ts(traffic_selector_t *ts)
{
chunk_t from, to;
uint8_t minbits = 0, maxbits = 0, unused;
host_t *net;
int bit, byte;
if (ts->to_subnet(ts, &net, &minbits))
{
unused = round_up(minbits, BITS_PER_BYTE) - minbits;
from = asn1_wrap(ASN1_BIT_STRING, "m",
chunk_cat("cc", chunk_from_thing(unused),
chunk_create(net->get_address(net).ptr,
(minbits + unused) / BITS_PER_BYTE)));
net->destroy(net);
return from;
}
net->destroy(net);
from = ts->get_from_address(ts);
for (byte = from.len - 1; byte >= 0; byte--)
{
if (from.ptr[byte] != 0)
{
minbits = byte * BITS_PER_BYTE + BITS_PER_BYTE;
for (bit = 0; bit < BITS_PER_BYTE; bit++)
{
if (from.ptr[byte] & 1 << bit)
{
break;
}
minbits--;
}
break;
}
}
to = ts->get_to_address(ts);
for (byte = to.len - 1; byte >= 0; byte--)
{
if (to.ptr[byte] != 0xFF)
{
maxbits = byte * BITS_PER_BYTE + BITS_PER_BYTE;
for (bit = 0; bit < BITS_PER_BYTE; bit++)
{
if ((to.ptr[byte] & 1 << bit) == 0)
{
break;
}
maxbits--;
}
break;
}
}
unused = round_up(minbits, BITS_PER_BYTE) - minbits;
from = asn1_wrap(ASN1_BIT_STRING, "m",
chunk_cat("cc", chunk_from_thing(unused),
chunk_create(from.ptr,
(minbits + unused) / BITS_PER_BYTE)));
unused = round_up(maxbits, BITS_PER_BYTE) - maxbits;
to = asn1_wrap(ASN1_BIT_STRING, "m",
chunk_cat("cc", chunk_from_thing(unused),
chunk_create(to.ptr,
(maxbits + unused) / BITS_PER_BYTE)));
return asn1_wrap(ASN1_SEQUENCE, "mm", from, to);
}
/**
* Generate and sign a new certificate
*/
@@ -2008,6 +2074,7 @@ static bool generate(private_x509_cert_t *cert, certificate_t *sign_cert,
chunk_t crlDistributionPoints = chunk_empty, authorityInfoAccess = chunk_empty;
chunk_t policyConstraints = chunk_empty, inhibitAnyPolicy = chunk_empty;
chunk_t ikeIntermediate = chunk_empty, msSmartcardLogon = chunk_empty;
chunk_t ipAddrBlocks = chunk_empty;
identification_t *issuer, *subject;
chunk_t key_info;
signature_scheme_t scheme;
@@ -2184,6 +2251,52 @@ static bool generate(private_x509_cert_t *cert, certificate_t *sign_cert,
}
}
if (cert->ipAddrBlocks->get_count(cert->ipAddrBlocks))
{
chunk_t v4blocks = chunk_empty, v6blocks = chunk_empty, block;
traffic_selector_t *ts;
enumerator = cert->ipAddrBlocks->create_enumerator(cert->ipAddrBlocks);
while (enumerator->enumerate(enumerator, &ts))
{
switch (ts->get_type(ts))
{
case TS_IPV4_ADDR_RANGE:
block = generate_ts(ts);
v4blocks = chunk_cat("mm", v4blocks, block);
break;
case TS_IPV6_ADDR_RANGE:
block = generate_ts(ts);
v6blocks = chunk_cat("mm", v6blocks, block);
break;
default:
break;
}
}
enumerator->destroy(enumerator);
if (v4blocks.ptr)
{
v4blocks = asn1_wrap(ASN1_SEQUENCE, "mm",
asn1_wrap(ASN1_OCTET_STRING, "c",
chunk_from_chars(0x00,0x01)),
asn1_wrap(ASN1_SEQUENCE, "m", v4blocks));
}
if (v6blocks.ptr)
{
v6blocks = asn1_wrap(ASN1_SEQUENCE, "mm",
asn1_wrap(ASN1_OCTET_STRING, "c",
chunk_from_chars(0x00,0x02)),
asn1_wrap(ASN1_SEQUENCE, "m", v6blocks));
}
ipAddrBlocks = asn1_wrap(ASN1_SEQUENCE, "mm",
asn1_build_known_oid(OID_IP_ADDR_BLOCKS),
asn1_wrap(ASN1_OCTET_STRING, "m",
asn1_wrap(ASN1_SEQUENCE, "mm",
v4blocks, v6blocks)));
cert->flags |= X509_IP_ADDR_BLOCKS;
}
if (cert->permitted_names->get_count(cert->permitted_names) ||
cert->excluded_names->get_count(cert->excluded_names))
{
@@ -2321,15 +2434,16 @@ static bool generate(private_x509_cert_t *cert, certificate_t *sign_cert,
}
if (basicConstraints.ptr || subjectAltNames.ptr || authKeyIdentifier.ptr ||
crlDistributionPoints.ptr || nameConstraints.ptr)
crlDistributionPoints.ptr || nameConstraints.ptr || ipAddrBlocks.ptr)
{
extensions = asn1_wrap(ASN1_CONTEXT_C_3, "m",
asn1_wrap(ASN1_SEQUENCE, "mmmmmmmmmmmmm",
asn1_wrap(ASN1_SEQUENCE, "mmmmmmmmmmmmmm",
basicConstraints, keyUsage, subjectKeyIdentifier,
authKeyIdentifier, subjectAltNames,
extendedKeyUsage, crlDistributionPoints,
authorityInfoAccess, nameConstraints, certPolicies,
policyMappings, policyConstraints, inhibitAnyPolicy));
policyMappings, policyConstraints, inhibitAnyPolicy,
ipAddrBlocks));
}
cert->tbsCertificate = asn1_wrap(ASN1_SEQUENCE, "mmmcmcmm",
@@ -2492,6 +2606,22 @@ x509_cert_t *x509_cert_gen(certificate_type_t type, va_list args)
cert->pathLenConstraint = (constraint < 128) ?
constraint : X509_NO_CONSTRAINT;
continue;
case BUILD_ADDRBLOCKS:
{
enumerator_t *enumerator;
traffic_selector_t *ts;
linked_list_t *list;
list = va_arg(args, linked_list_t*);
enumerator = list->create_enumerator(list);
while (enumerator->enumerate(enumerator, &ts))
{
cert->ipAddrBlocks->insert_last(cert->ipAddrBlocks,
ts->clone(ts));
}
enumerator->destroy(enumerator);
continue;
}
case BUILD_PERMITTED_NAME_CONSTRAINTS:
{
enumerator_t *enumerator;
+16 -1
View File
@@ -71,6 +71,7 @@ static int issue()
char *error = NULL, *keyid = NULL;
identification_t *id = NULL;
linked_list_t *san, *cdps, *ocsp, *permitted, *excluded, *policies, *mappings;
linked_list_t *addrblocks;
int pathlen = X509_NO_CONSTRAINT, inhibit_any = X509_NO_CONSTRAINT;
int inhibit_mapping = X509_NO_CONSTRAINT, require_explicit = X509_NO_CONSTRAINT;
chunk_t serial = chunk_empty;
@@ -81,6 +82,7 @@ static int issue()
x509_t *x509;
x509_cdp_t *cdp = NULL;
x509_cert_policy_t *policy = NULL;
traffic_selector_t *ts;
char *arg;
san = linked_list_create();
@@ -90,6 +92,7 @@ static int issue()
excluded = linked_list_create();
policies = linked_list_create();
mappings = linked_list_create();
addrblocks = linked_list_create();
while (TRUE)
{
@@ -184,6 +187,15 @@ static int issue()
case 'p':
pathlen = atoi(arg);
continue;
case 'B':
ts = parse_ts(arg);
if (!ts)
{
error = "invalid addressBlock";
goto usage;
}
addrblocks->insert_last(addrblocks, ts);
continue;
case 'n':
permitted->insert_last(permitted,
identification_create_from_string(arg));
@@ -519,7 +531,7 @@ static int issue()
BUILD_NOT_BEFORE_TIME, not_before, BUILD_DIGEST_ALG, digest,
BUILD_NOT_AFTER_TIME, not_after, BUILD_SERIAL, serial,
BUILD_SUBJECT_ALTNAMES, san, BUILD_X509_FLAG, flags,
BUILD_PATHLEN, pathlen,
BUILD_PATHLEN, pathlen, BUILD_ADDRBLOCKS, addrblocks,
BUILD_CRL_DISTRIBUTION_POINTS, cdps,
BUILD_OCSP_ACCESS_LOCATIONS, ocsp,
BUILD_PERMITTED_NAME_CONSTRAINTS, permitted,
@@ -557,6 +569,7 @@ end:
san->destroy_offset(san, offsetof(identification_t, destroy));
permitted->destroy_offset(permitted, offsetof(identification_t, destroy));
excluded->destroy_offset(excluded, offsetof(identification_t, destroy));
addrblocks->destroy_offset(addrblocks, offsetof(traffic_selector_t, destroy));
policies->destroy_function(policies, (void*)destroy_cert_policy);
mappings->destroy_function(mappings, (void*)destroy_policy_mapping);
cdps->destroy_function(cdps, (void*)destroy_cdp);
@@ -575,6 +588,7 @@ usage:
san->destroy_offset(san, offsetof(identification_t, destroy));
permitted->destroy_offset(permitted, offsetof(identification_t, destroy));
excluded->destroy_offset(excluded, offsetof(identification_t, destroy));
addrblocks->destroy_offset(addrblocks, offsetof(traffic_selector_t, destroy));
policies->destroy_function(policies, (void*)destroy_cert_policy);
mappings->destroy_function(mappings, (void*)destroy_policy_mapping);
cdps->destroy_function(cdps, (void*)destroy_cdp);
@@ -616,6 +630,7 @@ static void __attribute__ ((constructor))reg()
{"serial", 's', 1, "serial number in hex, default: random"},
{"ca", 'b', 0, "include CA basicConstraint, default: no"},
{"pathlen", 'p', 1, "set path length constraint"},
{"addrblock", 'B', 1, "RFC 3779 addrBlock to include"},
{"nc-permitted", 'n', 1, "add permitted NameConstraint"},
{"nc-excluded", 'N', 1, "add excluded NameConstraint"},
{"cert-policy", 'P', 1, "certificatePolicy OID to include"},
+17
View File
@@ -22,6 +22,7 @@
#include <collections/linked_list.h>
#include <credentials/certificates/certificate.h>
#include <credentials/certificates/x509.h>
#include <selectors/traffic_selector.h>
#include <asn1/asn1.h>
/**
@@ -57,6 +58,7 @@ static int self()
char *file = NULL, *dn = NULL, *hex = NULL, *error = NULL, *keyid = NULL;
identification_t *id = NULL;
linked_list_t *san, *ocsp, *permitted, *excluded, *policies, *mappings;
linked_list_t *addrblocks;
int pathlen = X509_NO_CONSTRAINT, inhibit_any = X509_NO_CONSTRAINT;
int inhibit_mapping = X509_NO_CONSTRAINT;
int require_explicit = X509_NO_CONSTRAINT;
@@ -66,6 +68,7 @@ static int self()
char *datenb = NULL, *datena = NULL, *dateform = NULL;
x509_flag_t flags = 0;
x509_cert_policy_t *policy = NULL;
traffic_selector_t *ts;
char *arg;
san = linked_list_create();
@@ -74,6 +77,7 @@ static int self()
excluded = linked_list_create();
policies = linked_list_create();
mappings = linked_list_create();
addrblocks = linked_list_create();
while (TRUE)
{
@@ -153,6 +157,15 @@ static int self()
case 'p':
pathlen = atoi(arg);
continue;
case 'B':
ts = parse_ts(arg);
if (!ts)
{
error = "invalid addressBlock";
goto usage;
}
addrblocks->insert_last(addrblocks, ts);
continue;
case 'n':
permitted->insert_last(permitted,
identification_create_from_string(arg));
@@ -360,6 +373,7 @@ static int self()
BUILD_NOT_AFTER_TIME, not_after, BUILD_SERIAL, serial,
BUILD_DIGEST_ALG, digest, BUILD_X509_FLAG, flags,
BUILD_PATHLEN, pathlen, BUILD_SUBJECT_ALTNAMES, san,
BUILD_ADDRBLOCKS, addrblocks,
BUILD_OCSP_ACCESS_LOCATIONS, ocsp,
BUILD_PERMITTED_NAME_CONSTRAINTS, permitted,
BUILD_EXCLUDED_NAME_CONSTRAINTS, excluded,
@@ -394,6 +408,7 @@ end:
san->destroy_offset(san, offsetof(identification_t, destroy));
permitted->destroy_offset(permitted, offsetof(identification_t, destroy));
excluded->destroy_offset(excluded, offsetof(identification_t, destroy));
addrblocks->destroy_offset(addrblocks, offsetof(traffic_selector_t, destroy));
policies->destroy_function(policies, (void*)destroy_cert_policy);
mappings->destroy_function(mappings, (void*)destroy_policy_mapping);
ocsp->destroy(ocsp);
@@ -411,6 +426,7 @@ usage:
san->destroy_offset(san, offsetof(identification_t, destroy));
permitted->destroy_offset(permitted, offsetof(identification_t, destroy));
excluded->destroy_offset(excluded, offsetof(identification_t, destroy));
addrblocks->destroy_offset(addrblocks, offsetof(traffic_selector_t, destroy));
policies->destroy_function(policies, (void*)destroy_cert_policy);
mappings->destroy_function(mappings, (void*)destroy_policy_mapping);
ocsp->destroy(ocsp);
@@ -449,6 +465,7 @@ static void __attribute__ ((constructor))reg()
{"serial", 's', 1, "serial number in hex, default: random"},
{"ca", 'b', 0, "include CA basicConstraint, default: no"},
{"pathlen", 'p', 1, "set path length constraint"},
{"addrblock", 'B', 1, "RFC 3779 addrBlock to include"},
{"nc-permitted", 'n', 1, "add permitted NameConstraint"},
{"nc-excluded", 'N', 1, "add excluded NameConstraint"},
{"cert-policy", 'P', 1, "certificatePolicy OID to include"},
+9
View File
@@ -24,6 +24,7 @@ pki \-\-issue \- Issue a certificate using a CA certificate and key
.OP \-\-ocsp uri
.OP \-\-pathlen len
.OP \-\-nc-permitted name
.OP \-\-addrblock block
.OP \-\-nc-excluded name
.OP \-\-policy\-mapping mapping
.OP \-\-policy\-explicit len
@@ -148,6 +149,14 @@ times.
.BI "\-p, \-\-pathlen " len
Set path length constraint.
.TP
.BI "\-B, \-\-addrblock " block
RFC 3779 address block to include in certificate. \fIblock\fR is either a
CIDR subnet (such as \fI10.0.0.0/8\fR) or an arbitrary address range
(\fI192.168.1.7-192.168.1.13\fR). Can be repeated to include multiple blocks.
Please note that the supplied blocks are included in the certificate as is,
so for standards compliance, multiple blocks must be supplied in correct
order and adjacent blocks must be combined. Refer to RFC 3779 for details.
.TP
.BI "\-n, \-\-nc-permitted " name
Add permitted NameConstraint extension to certificate. For DNS or email
constraints, the identity type is not always detectable by the given name. Use
+9
View File
@@ -22,6 +22,7 @@ pki \-\-self \- Create a self-signed certificate
.OP \-\-ca
.OP \-\-ocsp uri
.OP \-\-pathlen len
.OP \-\-addrblock block
.OP \-\-nc-permitted name
.OP \-\-nc-excluded name
.OP \-\-policy\-mapping mapping
@@ -127,6 +128,14 @@ times.
.BI "\-p, \-\-pathlen " len
Set path length constraint.
.TP
.BI "\-B, \-\-addrblock " block
RFC 3779 address block to include in certificate. \fIblock\fR is either a
CIDR subnet (such as \fI10.0.0.0/8\fR) or an arbitrary address range
(\fI192.168.1.7-192.168.1.13\fR). Can be repeated to include multiple blocks.
Please note that the supplied blocks are included in the certificate as is,
so for standards compliance, multiple blocks must be supplied in correct
order and adjacent blocks must be combined. Refer to RFC 3779 for details.
.TP
.BI "\-n, \-\-nc-permitted " name
Add permitted NameConstraint extension to certificate. For DNS or email
constraints, the identity type is not always detectable by the given name. Use
+22
View File
@@ -258,6 +258,28 @@ hash_algorithm_t get_default_digest(private_key_t *private)
return alg == HASH_UNKNOWN ? HASH_SHA256 : alg;
}
/*
* Described in header
*/
traffic_selector_t* parse_ts(char *str)
{
ts_type_t type = TS_IPV4_ADDR_RANGE;
char *to, from[64];
if (strchr(str, ':'))
{
type = TS_IPV6_ADDR_RANGE;
}
to = strchr(str, '-');
if (to)
{
snprintf(from, sizeof(from), "%.*s", to - str, str);
to++;
return traffic_selector_create_from_string(0, type, from, 0, to, 65535);
}
return traffic_selector_create_from_cidr(str, 0, 0, 65535);
}
/**
* Callback credential set pki uses
*/
+9
View File
@@ -26,6 +26,7 @@
#include "command.h"
#include <library.h>
#include <selectors/traffic_selector.h>
#include <credentials/keys/private_key.h>
/**
@@ -63,4 +64,12 @@ void set_file_mode(FILE *stream, cred_encoding_type_t enc);
*/
hash_algorithm_t get_default_digest(private_key_t *private);
/**
* Create a traffic selector from a CIDR or range string.
*
* @param str input string, either a.b.c.d/e or a.b.c.d-e.f.g.h
* @return traffic selector, NULL on error
*/
traffic_selector_t* parse_ts(char *str);
#endif /** PKI_H_ @}*/