diff options
author | Martin Willi <martin@strongswan.org> | 2017-02-27 09:37:51 +0100 |
---|---|---|
committer | Martin Willi <martin@strongswan.org> | 2017-02-27 09:37:51 +0100 |
commit | ae69863d4eb5735f2edebde2d0ccb56aa9a7a71e (patch) | |
tree | f3ad847e8f790c751bb7dd42aed59db26422952c /src | |
parent | ac4942c3c35c2a81846d7e4c1707598a53fd13c9 (diff) | |
parent | 2d7f940f11f14cf38f0d374ffd74aeb81a68f143 (diff) | |
download | strongswan-ae69863d4eb5735f2edebde2d0ccb56aa9a7a71e.tar.bz2 strongswan-ae69863d4eb5735f2edebde2d0ccb56aa9a7a71e.tar.xz |
Merge branch 'pki-addrblock'
Add support to the x509 plugin and pki to generate certificates with the
RFC 3779 addrblock extension.
Diffstat (limited to 'src')
-rw-r--r-- | src/libstrongswan/credentials/builder.c | 1 | ||||
-rw-r--r-- | src/libstrongswan/credentials/builder.h | 2 | ||||
-rw-r--r-- | src/libstrongswan/plugins/x509/x509_cert.c | 136 | ||||
-rw-r--r-- | src/pki/commands/issue.c | 17 | ||||
-rw-r--r-- | src/pki/commands/self.c | 17 | ||||
-rw-r--r-- | src/pki/man/pki---issue.1.in | 9 | ||||
-rw-r--r-- | src/pki/man/pki---self.1.in | 9 | ||||
-rw-r--r-- | src/pki/pki.c | 22 | ||||
-rw-r--r-- | src/pki/pki.h | 9 |
9 files changed, 218 insertions, 4 deletions
diff --git a/src/libstrongswan/credentials/builder.c b/src/libstrongswan/credentials/builder.c index 243dfd7cf..baa17c47d 100644 --- a/src/libstrongswan/credentials/builder.c +++ b/src/libstrongswan/credentials/builder.c @@ -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", diff --git a/src/libstrongswan/credentials/builder.h b/src/libstrongswan/credentials/builder.h index 7d1139348..1c6f5001b 100644 --- a/src/libstrongswan/credentials/builder.h +++ b/src/libstrongswan/credentials/builder.h @@ -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* */ diff --git a/src/libstrongswan/plugins/x509/x509_cert.c b/src/libstrongswan/plugins/x509/x509_cert.c index 2b83f3328..b77c5db4d 100644 --- a/src/libstrongswan/plugins/x509/x509_cert.c +++ b/src/libstrongswan/plugins/x509/x509_cert.c @@ -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; diff --git a/src/pki/commands/issue.c b/src/pki/commands/issue.c index d95f53c03..333c6ebb3 100644 --- a/src/pki/commands/issue.c +++ b/src/pki/commands/issue.c @@ -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"}, diff --git a/src/pki/commands/self.c b/src/pki/commands/self.c index 1899daac9..b894ac190 100644 --- a/src/pki/commands/self.c +++ b/src/pki/commands/self.c @@ -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"}, diff --git a/src/pki/man/pki---issue.1.in b/src/pki/man/pki---issue.1.in index ba5886f5f..d1fa3473f 100644 --- a/src/pki/man/pki---issue.1.in +++ b/src/pki/man/pki---issue.1.in @@ -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 diff --git a/src/pki/man/pki---self.1.in b/src/pki/man/pki---self.1.in index 81f59bbb2..4384fa72d 100644 --- a/src/pki/man/pki---self.1.in +++ b/src/pki/man/pki---self.1.in @@ -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 diff --git a/src/pki/pki.c b/src/pki/pki.c index 472704945..00fffefa6 100644 --- a/src/pki/pki.c +++ b/src/pki/pki.c @@ -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 */ diff --git a/src/pki/pki.h b/src/pki/pki.h index 017e61df6..54be59f8f 100644 --- a/src/pki/pki.h +++ b/src/pki/pki.h @@ -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_ @}*/ |