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:
@@ -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",
|
||||
|
||||
@@ -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* */
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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"},
|
||||
|
||||
@@ -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"},
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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_ @}*/
|
||||
|
||||
Reference in New Issue
Block a user