summaryrefslogtreecommitdiff
path: root/src/pki/commands
diff options
context:
space:
mode:
Diffstat (limited to 'src/pki/commands')
-rw-r--r--src/pki/commands/acert.c292
-rw-r--r--src/pki/commands/issue.c34
-rw-r--r--src/pki/commands/print.c95
-rw-r--r--src/pki/commands/self.c33
-rw-r--r--src/pki/commands/signcrl.c28
5 files changed, 462 insertions, 20 deletions
diff --git a/src/pki/commands/acert.c b/src/pki/commands/acert.c
new file mode 100644
index 000000000..d49365db5
--- /dev/null
+++ b/src/pki/commands/acert.c
@@ -0,0 +1,292 @@
+/*
+ * Copyright (C) 2009 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <time.h>
+#include <errno.h>
+
+#include "pki.h"
+
+#include <utils/debug.h>
+#include <asn1/asn1.h>
+#include <collections/linked_list.h>
+#include <credentials/certificates/certificate.h>
+#include <credentials/certificates/x509.h>
+#include <credentials/certificates/ac.h>
+
+/**
+ * Issue an attribute certificate
+ */
+static int acert()
+{
+ cred_encoding_type_t form = CERT_ASN1_DER;
+ hash_algorithm_t digest = HASH_SHA1;
+ certificate_t *ac = NULL, *cert = NULL, *issuer =NULL;
+ private_key_t *private = NULL;
+ public_key_t *public = NULL;
+ char *file = NULL, *hex = NULL, *issuercert = NULL, *issuerkey = NULL;
+ char *error = NULL, *keyid = NULL;
+ linked_list_t *groups;
+ chunk_t serial = chunk_empty, encoding = chunk_empty;
+ time_t not_before, not_after, lifetime = 24 * 60 * 60;
+ char *datenb = NULL, *datena = NULL, *dateform = NULL;
+ rng_t *rng;
+ char *arg;
+
+ groups = linked_list_create();
+
+ while (TRUE)
+ {
+ switch (command_getopt(&arg))
+ {
+ case 'h':
+ goto usage;
+ case 'g':
+ digest = enum_from_name(hash_algorithm_short_names, arg);
+ if (digest == -1)
+ {
+ error = "invalid --digest type";
+ goto usage;
+ }
+ continue;
+ case 'i':
+ file = arg;
+ continue;
+ case 'm':
+ groups->insert_last(groups, arg);
+ continue;
+ case 'c':
+ issuercert = arg;
+ continue;
+ case 'k':
+ issuerkey = arg;
+ continue;
+ case 'x':
+ keyid = arg;
+ continue;
+ case 'l':
+ lifetime = atoi(arg) * 60 * 60;
+ if (!lifetime)
+ {
+ error = "invalid --lifetime value";
+ goto usage;
+ }
+ continue;
+ case 'D':
+ dateform = arg;
+ continue;
+ case 'F':
+ datenb = arg;
+ continue;
+ case 'T':
+ datena = arg;
+ continue;
+ case 's':
+ hex = arg;
+ continue;
+ case 'f':
+ if (!get_form(arg, &form, CRED_CERTIFICATE))
+ {
+ error = "invalid output format";
+ goto usage;
+ }
+ continue;
+ case EOF:
+ break;
+ default:
+ error = "invalid --acert option";
+ goto usage;
+ }
+ break;
+ }
+
+ if (!calculate_lifetime(dateform, datenb, datena, lifetime,
+ &not_before, &not_after))
+ {
+ error = "invalid --not-before/after datetime";
+ goto usage;
+ }
+
+ if (!issuercert)
+ {
+ error = "--issuercert is required";
+ goto usage;
+ }
+ if (!issuerkey && !keyid)
+ {
+ error = "--issuerkey or --issuerkeyid is required";
+ goto usage;
+ }
+
+ issuer = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
+ BUILD_FROM_FILE, issuercert, BUILD_END);
+ if (!issuer)
+ {
+ error = "parsing issuer certificate failed";
+ goto end;
+ }
+ public = issuer->get_public_key(issuer);
+ if (!public)
+ {
+ error = "extracting issuer certificate public key failed";
+ goto end;
+ }
+ if (issuerkey)
+ {
+ private = lib->creds->create(lib->creds, CRED_PRIVATE_KEY,
+ public->get_type(public),
+ BUILD_FROM_FILE, issuerkey, BUILD_END);
+ }
+ else
+ {
+ chunk_t chunk;
+
+ chunk = chunk_from_hex(chunk_create(keyid, strlen(keyid)), NULL);
+ private = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_ANY,
+ BUILD_PKCS11_KEYID, chunk, BUILD_END);
+ free(chunk.ptr);
+ }
+ if (!private)
+ {
+ error = "loading issuer private key failed";
+ goto end;
+ }
+ if (!private->belongs_to(private, public))
+ {
+ error = "issuer private key does not match issuer certificate";
+ goto end;
+ }
+
+ if (hex)
+ {
+ serial = chunk_from_hex(chunk_create(hex, strlen(hex)), NULL);
+ }
+ else
+ {
+ rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
+ if (!rng)
+ {
+ error = "no random number generator found";
+ goto end;
+ }
+ if (!rng_allocate_bytes_not_zero(rng, 8, &serial, FALSE))
+ {
+ error = "failed to generate serial number";
+ rng->destroy(rng);
+ goto end;
+ }
+ serial.ptr[0] &= 0x7F;
+ rng->destroy(rng);
+ }
+
+ if (file)
+ {
+ cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
+ BUILD_FROM_FILE, file, BUILD_END);
+ }
+ else
+ {
+ if (!chunk_from_fd(0, &encoding))
+ {
+ fprintf(stderr, "%s: ", strerror(errno));
+ error = "reading public key failed";
+ goto end;
+ }
+ cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
+ BUILD_BLOB, encoding, BUILD_END);
+ chunk_free(&encoding);
+ }
+ if (!cert)
+ {
+ error = "parsing user certificate failed";
+ goto end;
+ }
+
+ ac = lib->creds->create(lib->creds,
+ CRED_CERTIFICATE, CERT_X509_AC,
+ BUILD_CERT, cert,
+ BUILD_NOT_BEFORE_TIME, not_before,
+ BUILD_NOT_AFTER_TIME, not_after,
+ BUILD_SERIAL, serial,
+ BUILD_AC_GROUP_STRINGS, groups,
+ BUILD_SIGNING_CERT, issuer,
+ BUILD_SIGNING_KEY, private,
+ BUILD_END);
+ if (!ac)
+ {
+ error = "generating attribute certificate failed";
+ goto end;
+ }
+ if (!ac->get_encoding(ac, form, &encoding))
+ {
+ error = "encoding attribute certificate failed";
+ goto end;
+ }
+ if (fwrite(encoding.ptr, encoding.len, 1, stdout) != 1)
+ {
+ error = "writing attribute certificate key failed";
+ goto end;
+ }
+
+end:
+ DESTROY_IF(ac);
+ DESTROY_IF(cert);
+ DESTROY_IF(issuer);
+ DESTROY_IF(public);
+ DESTROY_IF(private);
+ groups->destroy(groups);
+ free(encoding.ptr);
+ free(serial.ptr);
+
+ if (error)
+ {
+ fprintf(stderr, "%s\n", error);
+ return 1;
+ }
+ return 0;
+
+usage:
+ groups->destroy(groups);
+ return command_usage(error);
+}
+
+/**
+ * Register the command.
+ */
+static void __attribute__ ((constructor))reg()
+{
+ command_register((command_t) {
+ acert, 'z', "acert",
+ "issue an attribute certificate",
+ {"[--in file] [--group name]* --issuerkey file|--issuerkeyid hex",
+ " --issuercert file [--serial hex] [--lifetime hours]",
+ " [--not-before datetime] [--not-after datetime] [--dateform form]",
+ "[--digest md5|sha1|sha224|sha256|sha384|sha512] [--outform der|pem]"},
+ {
+ {"help", 'h', 0, "show usage information"},
+ {"in", 'i', 1, "holder certificate, default: stdin"},
+ {"group", 'm', 1, "group membership string to include"},
+ {"issuercert", 'c', 1, "issuer certificate file"},
+ {"issuerkey", 'k', 1, "issuer private key file"},
+ {"issuerkeyid", 'x', 1, "keyid on smartcard of issuer private key"},
+ {"serial", 's', 1, "serial number in hex, default: random"},
+ {"lifetime", 'l', 1, "hours the acert is valid, default: 24"},
+ {"not-before", 'F', 1, "date/time the validity of the AC starts"},
+ {"not-after", 'T', 1, "date/time the validity of the AC ends"},
+ {"dateform", 'D', 1, "strptime(3) input format, default: %d.%m.%y %T"},
+ {"digest", 'g', 1, "digest for signature creation, default: sha1"},
+ {"outform", 'f', 1, "encoding of generated cert, default: der"},
+ }
+ });
+}
diff --git a/src/pki/commands/issue.c b/src/pki/commands/issue.c
index d5c33b89f..d03326e3d 100644
--- a/src/pki/commands/issue.c
+++ b/src/pki/commands/issue.c
@@ -72,8 +72,8 @@ static int issue()
int inhibit_mapping = X509_NO_CONSTRAINT, require_explicit = X509_NO_CONSTRAINT;
chunk_t serial = chunk_empty;
chunk_t encoding = chunk_empty;
- time_t lifetime = 1095;
- time_t not_before, not_after;
+ time_t not_before, not_after, lifetime = 1095 * 24 * 60 * 60;
+ char *datenb = NULL, *datena = NULL, *dateform = NULL;
x509_flag_t flags = 0;
x509_t *x509;
x509_cdp_t *cdp = NULL;
@@ -132,13 +132,22 @@ static int issue()
san->insert_last(san, identification_create_from_string(arg));
continue;
case 'l':
- lifetime = atoi(arg);
+ lifetime = atoi(arg) * 24 * 60 * 60;
if (!lifetime)
{
error = "invalid --lifetime value";
goto usage;
}
continue;
+ case 'D':
+ dateform = arg;
+ continue;
+ case 'F':
+ datenb = arg;
+ continue;
+ case 'T':
+ datena = arg;
+ continue;
case 's':
hex = arg;
continue;
@@ -242,6 +251,10 @@ static int issue()
{
flags |= X509_OCSP_SIGNER;
}
+ else if (streq(arg, "msSmartcardLogon"))
+ {
+ flags |= X509_MS_SMARTCARD_LOGON;
+ }
continue;
case 'f':
if (!get_form(arg, &form, CRED_CERTIFICATE))
@@ -285,6 +298,12 @@ static int issue()
error = "--cakey or --keyid is required";
goto usage;
}
+ if (!calculate_lifetime(dateform, datenb, datena, lifetime,
+ &not_before, &not_after))
+ {
+ error = "invalid --not-before/after datetime";
+ goto usage;
+ }
if (dn && *dn)
{
id = identification_create_from_string(dn);
@@ -363,6 +382,7 @@ static int issue()
rng->destroy(rng);
goto end;
}
+ serial.ptr[0] &= 0x7F;
rng->destroy(rng);
}
@@ -454,9 +474,6 @@ static int issue()
chunk_from_chars(ASN1_SEQUENCE, 0));
}
- not_before = time(NULL);
- not_after = not_before + lifetime * 24 * 60 * 60;
-
cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
BUILD_SIGNING_KEY, private, BUILD_SIGNING_CERT, ca,
BUILD_PUBLIC_KEY, public, BUILD_SUBJECT, id,
@@ -536,7 +553,7 @@ static void __attribute__ ((constructor))reg()
{"[--in file] [--type pub|pkcs10] --cakey file|--cakeyid hex",
" --cacert file [--dn subject-dn] [--san subjectAltName]+",
"[--lifetime days] [--serial hex] [--ca] [--pathlen len]",
- "[--flag serverAuth|clientAuth|crlSign|ocspSigning]+",
+ "[--flag serverAuth|clientAuth|crlSign|ocspSigning|msSmartcardLogon]+",
"[--crl uri [--crlissuer i]]+ [--ocsp uri]+ [--nc-permitted name]",
"[--nc-excluded name] [--policy-mapping issuer-oid:subject-oid]",
"[--policy-explicit len] [--policy-inhibit len] [--policy-any len]",
@@ -552,6 +569,9 @@ static void __attribute__ ((constructor))reg()
{"dn", 'd', 1, "distinguished name to include as subject"},
{"san", 'a', 1, "subjectAltName to include in certificate"},
{"lifetime", 'l', 1, "days the certificate is valid, default: 1095"},
+ {"not-before", 'F', 1, "date/time the validity of the cert starts"},
+ {"not-after", 'T', 1, "date/time the validity of the cert ends"},
+ {"dateform", 'D', 1, "strptime(3) input format, default: %d.%m.%y %T"},
{"serial", 's', 1, "serial number in hex, default: random"},
{"ca", 'b', 0, "include CA basicConstraint, default: no"},
{"pathlen", 'p', 1, "set path length constraint"},
diff --git a/src/pki/commands/print.c b/src/pki/commands/print.c
index 077c1ef3e..15ace035d 100644
--- a/src/pki/commands/print.c
+++ b/src/pki/commands/print.c
@@ -16,9 +16,11 @@
#include "pki.h"
#include <asn1/asn1.h>
+#include <asn1/oid.h>
#include <credentials/certificates/certificate.h>
#include <credentials/certificates/x509.h>
#include <credentials/certificates/crl.h>
+#include <credentials/certificates/ac.h>
#include <selectors/traffic_selector.h>
#include <time.h>
@@ -138,6 +140,10 @@ static void print_x509(x509_t *x509)
{
printf("iKEIntermediate ");
}
+ if (flags & X509_MS_SMARTCARD_LOGON)
+ {
+ printf("msSmartcardLogon ");
+ }
if (flags & X509_SELF_SIGNED)
{
printf("self-signed ");
@@ -388,6 +394,85 @@ static void print_crl(crl_t *crl)
}
/**
+ * Print AC specific information
+ */
+static void print_ac(ac_t *ac)
+{
+ ac_group_type_t type;
+ identification_t *id;
+ enumerator_t *groups;
+ chunk_t chunk;
+ bool first = TRUE;
+
+ chunk = chunk_skip_zero(ac->get_serial(ac));
+ printf("serial: %#B\n", &chunk);
+
+ id = ac->get_holderIssuer(ac);
+ if (id)
+ {
+ printf("hissuer: \"%Y\"\n", id);
+ }
+ chunk = chunk_skip_zero(ac->get_holderSerial(ac));
+ if (chunk.ptr)
+ {
+ printf("hserial: %#B\n", &chunk);
+ }
+ groups = ac->create_group_enumerator(ac);
+ while (groups->enumerate(groups, &type, &chunk))
+ {
+ int oid;
+ char *str;
+
+ if (first)
+ {
+ printf("groups: ");
+ first = FALSE;
+ }
+ else
+ {
+ printf(" ");
+ }
+ switch (type)
+ {
+ case AC_GROUP_TYPE_STRING:
+ printf("%.*s", (int)chunk.len, chunk.ptr);
+ break;
+ case AC_GROUP_TYPE_OID:
+ oid = asn1_known_oid(chunk);
+ if (oid == OID_UNKNOWN)
+ {
+ str = asn1_oid_to_string(chunk);
+ if (str)
+ {
+ printf("%s", str);
+ free(str);
+ }
+ else
+ {
+ printf("OID:%#B", &chunk);
+ }
+ }
+ else
+ {
+ printf("%s", oid_names[oid].name);
+ }
+ break;
+ case AC_GROUP_TYPE_OCTETS:
+ printf("%#B", &chunk);
+ break;
+ }
+ printf("\n");
+ }
+ groups->destroy(groups);
+
+ chunk = ac->get_authKeyIdentifier(ac);
+ if (chunk.ptr)
+ {
+ printf("authkey: %#B\n", &chunk);
+ }
+}
+
+/**
* Print certificate information
*/
static void print_cert(certificate_t *cert)
@@ -432,6 +517,9 @@ static void print_cert(certificate_t *cert)
case CERT_X509_CRL:
print_crl((crl_t*)cert);
break;
+ case CERT_X509_AC:
+ print_ac((ac_t*)cert);
+ break;
default:
printf("parsing certificate subtype %N not implemented\n",
certificate_type_names, cert->get_type(cert));
@@ -472,6 +560,11 @@ static int print()
type = CRED_CERTIFICATE;
subtype = CERT_X509_CRL;
}
+ else if (streq(arg, "ac"))
+ {
+ type = CRED_CERTIFICATE;
+ subtype = CERT_X509_AC;
+ }
else if (streq(arg, "pub"))
{
type = CRED_PUBLIC_KEY;
@@ -558,7 +651,7 @@ static void __attribute__ ((constructor))reg()
command_register((command_t)
{ print, 'a', "print",
"print a credential in a human readable form",
- {"[--in file] [--type rsa-priv|ecdsa-priv|pub|x509|crl]"},
+ {"[--in file] [--type rsa-priv|ecdsa-priv|pub|x509|crl|ac]"},
{
{"help", 'h', 0, "show usage information"},
{"in", 'i', 1, "input file, default: stdin"},
diff --git a/src/pki/commands/self.c b/src/pki/commands/self.c
index c28c9c291..a35a42b89 100644
--- a/src/pki/commands/self.c
+++ b/src/pki/commands/self.c
@@ -60,8 +60,8 @@ static int self()
int inhibit_mapping = X509_NO_CONSTRAINT, require_explicit = X509_NO_CONSTRAINT;
chunk_t serial = chunk_empty;
chunk_t encoding = chunk_empty;
- time_t lifetime = 1095;
- time_t not_before, not_after;
+ time_t not_before, not_after, lifetime = 1095 * 24 * 60 * 60;
+ char *datenb = NULL, *datena = NULL, *dateform = NULL;
x509_flag_t flags = 0;
x509_cert_policy_t *policy = NULL;
char *arg;
@@ -115,13 +115,22 @@ static int self()
san->insert_last(san, identification_create_from_string(arg));
continue;
case 'l':
- lifetime = atoi(arg);
+ lifetime = atoi(arg) * 24 * 60 * 60;
if (!lifetime)
{
error = "invalid --lifetime value";
goto usage;
}
continue;
+ case 'D':
+ dateform = arg;
+ continue;
+ case 'F':
+ datenb = arg;
+ continue;
+ case 'T':
+ datena = arg;
+ continue;
case 's':
hex = arg;
continue;
@@ -225,6 +234,10 @@ static int self()
{
flags |= X509_OCSP_SIGNER;
}
+ else if (streq(arg, "msSmartcardLogon"))
+ {
+ flags |= X509_MS_SMARTCARD_LOGON;
+ }
continue;
case 'f':
if (!get_form(arg, &form, CRED_CERTIFICATE))
@@ -250,6 +263,12 @@ static int self()
error = "--dn is required";
goto usage;
}
+ if (!calculate_lifetime(dateform, datenb, datena, lifetime,
+ &not_before, &not_after))
+ {
+ error = "invalid --not-before/after datetime";
+ goto usage;
+ }
id = identification_create_from_string(dn);
if (id->get_type(id) != ID_DER_ASN1_DN)
{
@@ -314,10 +333,9 @@ static int self()
rng->destroy(rng);
goto end;
}
+ serial.ptr[0] &= 0x7F;
rng->destroy(rng);
}
- not_before = time(NULL);
- not_after = not_before + lifetime * 24 * 60 * 60;
cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
BUILD_SIGNING_KEY, private, BUILD_PUBLIC_KEY, public,
BUILD_SUBJECT, id, BUILD_NOT_BEFORE_TIME, not_before,
@@ -391,7 +409,7 @@ static void __attribute__ ((constructor))reg()
{" [--in file|--keyid hex] [--type rsa|ecdsa]",
" --dn distinguished-name [--san subjectAltName]+",
"[--lifetime days] [--serial hex] [--ca] [--ocsp uri]+",
- "[--flag serverAuth|clientAuth|crlSign|ocspSigning]+",
+ "[--flag serverAuth|clientAuth|crlSign|ocspSigning|msSmartcardLogon]+",
"[--nc-permitted name] [--nc-excluded name]",
"[--policy-map issuer-oid:subject-oid]",
"[--policy-explicit len] [--policy-inhibit len] [--policy-any len]",
@@ -405,6 +423,9 @@ static void __attribute__ ((constructor))reg()
{"dn", 'd', 1, "subject and issuer distinguished name"},
{"san", 'a', 1, "subjectAltName to include in certificate"},
{"lifetime", 'l', 1, "days the certificate is valid, default: 1095"},
+ {"not-before", 'F', 1, "date/time the validity of the cert starts"},
+ {"not-after", 'T', 1, "date/time the validity of the cert ends"},
+ {"dateform", 'D', 1, "strptime(3) input format, default: %d.%m.%y %T"},
{"serial", 's', 1, "serial number in hex, default: random"},
{"ca", 'b', 0, "include CA basicConstraint, default: no"},
{"pathlen", 'p', 1, "set path length constraint"},
diff --git a/src/pki/commands/signcrl.c b/src/pki/commands/signcrl.c
index 4f9dd291d..c9eebbf59 100644
--- a/src/pki/commands/signcrl.c
+++ b/src/pki/commands/signcrl.c
@@ -124,7 +124,8 @@ static int sign_crl()
int serial_len = 0;
crl_reason_t reason = CRL_REASON_UNSPECIFIED;
time_t thisUpdate, nextUpdate, date = time(NULL);
- time_t lifetime = 15;
+ time_t lifetime = 15 * 24 * 60 * 60;
+ char *datetu = NULL, *datenu = NULL, *dateform = NULL;
linked_list_t *list, *cdps;
enumerator_t *enumerator, *lastenum = NULL;
x509_cdp_t *cdp;
@@ -161,13 +162,22 @@ static int sign_crl()
lastupdate = arg;
continue;
case 'l':
- lifetime = atoi(arg);
+ lifetime = atoi(arg) * 24 * 60 * 60;
if (!lifetime)
{
- error = "invalid lifetime";
+ error = "invalid --lifetime value";
goto usage;
}
continue;
+ case 'D':
+ dateform = arg;
+ continue;
+ case 'F':
+ datetu = arg;
+ continue;
+ case 'T':
+ datenu = arg;
+ continue;
case 'z':
serial_len = read_serial(arg, serial, sizeof(serial));
if (serial_len < 0)
@@ -275,6 +285,12 @@ static int sign_crl()
error = "--cakey or --keyid is required";
goto usage;
}
+ if (!calculate_lifetime(dateform, datetu, datenu, lifetime,
+ &thisUpdate, &nextUpdate))
+ {
+ error = "invalid --this/next-update datetime";
+ goto usage;
+ }
ca = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
BUILD_FROM_FILE, cacert, BUILD_END);
@@ -321,9 +337,6 @@ static int sign_crl()
goto error;
}
- thisUpdate = time(NULL);
- nextUpdate = thisUpdate + lifetime * 24 * 60 * 60;
-
if (basecrl)
{
lastcrl = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509_CRL,
@@ -442,6 +455,9 @@ static void __attribute__ ((constructor))reg()
{"cakey", 'k', 1, "CA private key file"},
{"cakeyid", 'x', 1, "keyid on smartcard of CA private key"},
{"lifetime", 'l', 1, "days the CRL gets a nextUpdate, default: 15"},
+ {"this-update", 'F', 1, "date/time the validity of the CRL starts"},
+ {"next-update", 'T', 1, "date/time the validity of the CRL ends"},
+ {"dateform", 'D', 1, "strptime(3) input format, default: %d.%m.%y %T"},
{"lastcrl", 'a', 1, "CRL of lastUpdate to copy revocations from"},
{"basecrl", 'b', 1, "base CRL to create a delta CRL for"},
{"crluri", 'u', 1, "freshest delta CRL URI to include"},