#81 Implement support for MS V2 template extension
Merged 3 years ago by rcritten. Opened 3 years ago by ftweedal.
ftweedal/certmonger feature/certificate-template  into  master

file modified
+2
@@ -56,6 +56,7 @@ 

                 {("template-crldp"),array-of-string (CRL distribution point URIs)}

                 {("template-ns-comment"),string (Netscape comment)}

                 {("template-profile"),string (certificate profile)}

+                {("template-ms-certificate-template"),string (MS V2 template specifier; format: <oid>:<major-version>[:<minor-version>] )}

                 {("template-issuer"),string (requested issuer)}

                 {("template-challenge-password"),string (password to add to CSR)}

                 {("template-challenge-password-file"),string (password file)
@@ -165,6 +166,7 @@ 

                 {("template-crldp"),array-of-string (CRL distribution point URIs)}

                 {("template-ns-comment"),string (Netscape comment)}

                 {("template-profile"),string (certificate profile)}

+                {("template-ms-certificate-template"),string (MS V2 template specifier; format: <oid>:<major-version>[:<minor-version>] )}

                 {("template-issuer"),string (requested issuer)}

                 {("template-challenge-password"),string (password to add to CSR)}

                 {("template-challenge-password-file"),string (password file)

file modified
+3 -1
@@ -186,7 +186,7 @@ 

  tdbusm_check_LDADD = libcm.a $(CERTMONGER_LIBS) $(POPT_LIBS)

  serial_check_LDADD = libcm.a $(CERTMONGER_LIBS) $(LTLIBICONV)

  nl_check_LDADD = libcm.a $(CERTMONGER_LIBS)

- submit_x_CFLAGS = $(AM_CFLAGS) -DCM_SUBMIT_X_MAIN

+ submit_x_CFLAGS = $(AM_CFLAGS) $(NSS_CFLAGS) -DCM_SUBMIT_X_MAIN

  submit_x_SOURCES = submit-x.c submit-x.h submit-u.c submit-u.h log.c log.h \

  	tm.c tm.h

  submit_x_LDADD = $(XMLRPC_LIBS) $(KRB5_LIBS) $(TALLOC_LIBS) \
@@ -205,12 +205,14 @@ 

  pkglibexec_PROGRAMS += scep-submit

  endif

  noinst_PROGRAMS += submit-h submit-d

+ ipa_submit_CFLAGS = $(AM_CFLAGS) $(NSS_CFLAGS)

  ipa_submit_SOURCES = ipa.c srvloc.c srvloc.h store.h store-gen.c \

  		submit-x.c submit-x.h submit-u.c submit-u.h \

  		submit-e.h util.c util.h log.c log.h tm.c tm.h

  ipa_submit_LDADD = $(XMLRPC_LIBS) $(LDAP_LIBS) $(KRB5_LIBS) $(TALLOC_LIBS) \

  		   $(GMP_LIBS) $(IDN_LIBS) $(OPENSSL_LIBS) $(UUID_LIBS) \

  		   $(RESOLV_LIBS) $(LTLIBICONV) $(POPT_LIBS)

+ certmaster_submit_CFLAGS = $(AM_CFLAGS) $(NSS_CFLAGS)

  certmaster_submit_SOURCES = certmaster.c submit-x.c submit-x.h \

  		submit-e.h submit-u.c submit-u.h util.c util.h log.c log.h \

  		tm.c tm.h

file modified
+97 -2
@@ -69,7 +69,7 @@ 

  struct ms_template {

  	SECItem id;

  	SECItem major;

- 	SECItem *minor;

+ 	SECItem minor;

  };

  

  /* KerberosString: RFC 4120, 5.2.1 */
@@ -180,7 +180,7 @@ 

  	.kind = SEC_ASN1_SEQUENCE,

  	.offset = 0,

  	.sub = NULL,

- 	.size = sizeof(struct kerberos_principal_name),

+ 	.size = sizeof(struct ms_template),

  	},

  	{

  	.kind = SEC_ASN1_OBJECT_ID,
@@ -1601,6 +1601,89 @@ 

  	return item;

  }

  

+ /* Build a Microsoft certificate template extension value. */

+ static SECItem *

+ cm_certext_build_certificate_template(

+ 	PLArenaPool *arena,

+ 	char *template_spec)

+ {

+ 	struct ms_template template_data;

+ 	memset(&template_data, 0, sizeof(struct ms_template));

+ 

+ 	if (NULL == template_spec || *template_spec == '\0')

+ 		return NULL;

+ 

+ 	/* strtok overwrites delimiters with null bytes;

+ 	 * therefore duplicate the input string */

+ 	char *template_spec_dup = PORT_ArenaStrdup(arena, template_spec);

+ 	if (NULL == template_spec_dup)

+ 		return NULL;

+ 

+ 	int i = 0;

+ 	char *saveptr, *endptr;

+ 	for (

+ 		char *part = strtok_r(template_spec_dup, ":", &saveptr);

+ 		part != NULL;

+ 		part = strtok_r(NULL, ":", &saveptr)

+ 	) {

+ 		if (i == 0) {

+ 			// parse OID

+ 			if (SECSuccess != SEC_StringToOID(arena, &template_data.id, part, 0))

+ 				return NULL;

+ 		}

+ 		else if (i == 1) {

+ 			// parse major version

+ 			long x = strtol(part, &endptr, 10);

+ 			if (*part == '\0' || *endptr != '\0') {

+ 				// string was empty or contained non-digits

+ 				return NULL;

+ 			}

+ 			if (SEC_ASN1EncodeInteger(arena, &template_data.major, x)

+ 					!= &template_data.major)

+ 				return NULL;

+ 		}

+ 		else if (i == 2) {

+ 			// parse minor version

+ 			long x = strtol(part, &endptr, 10);

+ 			if (*part == '\0' || *endptr != '\0') {

+ 				// string was empty or contained non-digits

+ 				return NULL;

+ 			}

+ 			if (SEC_ASN1EncodeInteger(arena, &template_data.minor, x)

+ 					!= &template_data.minor)

+ 				return NULL;

+ 		}

+ 		else {

+ 			// there are too many parts!

+ 			return NULL;

+ 		}

+ 		i++;

+ 	}

+ 	if (i < 2) {

+ 		// there are too few parts! (OID and major version are required)

+ 		return NULL;

+ 	}

+ 

+ 	SECItem encoded;

+ 	if (SEC_ASN1EncodeItem(arena, &encoded, &template_data,

+ 			       cm_ms_template_template) != &encoded)

+ 		return NULL;

+ 	return SECITEM_ArenaDupItem(arena, &encoded);

+ }

+ 

+ /* Validate a V2 template spec */

+ PRBool cm_ms_template_valid(char *template_spec) {

+ 	PLArenaPool *arena = PORT_NewArena(sizeof(double));

+ 	if (arena == NULL)

+ 		return PR_FALSE;

+ 	SECItem *result =

+ 		cm_certext_build_certificate_template(arena, template_spec);

+ 	PORT_FreeArena(arena, PR_FALSE);

+ 	// *result has been freed, but we don't read it;

+ 	// we only need to know whether the parse succeeded

+ 	return result != NULL;

+ }

+ 

  /* Build a Netscape certtype extension value. */

  static SECItem *

  cm_certext_build_ns_certtype(struct cm_store_entry *entry,
@@ -1848,6 +1931,18 @@ 

  			i++;

  		}

  	}

+ 	if (entry->cm_template_certificate_template != NULL) {

+ 		oid = (SECOidData *) &oid_microsoft_certificate_template;

+ 		item = cm_certext_build_certificate_template(

+ 			arena, entry->cm_template_certificate_template);

+ 		if ((item != NULL) && (oid != NULL)) {

+ 			ext[i].id = oid->oid;

+ 			ext[i].critical = der_false;

+ 			ext[i].value = *item;

+ 			exts[i] = &ext[i];

+ 			i++;

+ 		}

+ 	}

  	if (entry->cm_template_ns_certtype != NULL) {

  		oid = SECOID_FindOIDByTag(SEC_OID_NS_CERT_EXT_CERT_TYPE);

  		item = cm_certext_build_ns_certtype(entry, arena,

file modified
+5
@@ -15,6 +15,8 @@ 

   * along with this program.  If not, see <http://www.gnu.org/licenses/>.

   */

  

+ #include <prtypes.h>

+ 

  #ifndef cmcertext_h

  #define cmcertext_h

  
@@ -25,4 +27,7 @@ 

  				     struct NSSInitContextStr *ctx,

  				     unsigned char **encoded, size_t *length);

  

+ /* Validate a V2 template spec */

+ PRBool cm_ms_template_valid(char *template_spec);

+ 

  #endif

file modified
+6
@@ -61,6 +61,12 @@ 

  Request a certificate using the named profile, template, or certtype,

  from the specified CA.

  .TP

+ \fB\-\-ms-template-spec\fR SPEC

+ Include a V2 Certificate Template extension in the signing request.

+ This datum includes an Object Identifier, a major version number

+ (positive integer) and an optional minor version number.  The format

+ is: \fB<oid>:<majorVersion>[:<minorVersion>]\fR.

+ .TP

  \fB\-X\fR NAME

  Request a certificate using the named issuer from the specified CA.

  .TP

@@ -88,6 +88,12 @@ 

  Request a certificate using the named profile, template, or certtype,

  from the specified CA.

  .TP

+ \fB\-\-ms-template-spec\fR SPEC

+ Include a V2 Certificate Template extension in the signing request.

+ This datum includes an Object Identifier, a major version number

+ (positive integer) and an optional minor version number.  The format

+ is: \fB<oid>:<majorVersion>[:<minorVersion>]\fR.

+ .TP

  \fB\-X\fR NAME

  Request a certificate using the named issuer from the specified CA.

  

@@ -48,6 +48,12 @@ 

  Request a certificate using the named profile, template, or certtype,

  from the specified CA.

  .TP

+ \fB\-\-ms-template-spec\fR SPEC

+ Include a V2 Certificate Template extension in the signing request.

+ This datum includes an Object Identifier, a major version number

+ (positive integer) and an optional minor version number.  The format

+ is: \fB<oid>:<majorVersion>[:<minorVersion>]\fR.

+ .TP

  \fB\-X\fR NAME

  Request a certificate using the named issuer from the specified CA.

  .TP

@@ -86,6 +86,12 @@ 

  Request a certificate using the named profile, template, or certtype,

  from the specified CA.

  .TP

+ \fB\-\-ms-template-spec\fR SPEC

+ Include a V2 Certificate Template extension in the signing request.

+ This datum includes an Object Identifier, a major version number

+ (positive integer) and an optional minor version number.  The format

+ is: \fB<oid>:<majorVersion>[:<minorVersion>]\fR.

+ .TP

  \fB\-X\fR NAME

  Request a certificate using the named issuer from the specified CA.

  

file modified
+46
@@ -748,6 +748,7 @@ 

  	int keysize = 0, auto_renew = 1, verbose = 0, ku = 0, kubit, c, i, j;

  	char *ca = DEFAULT_CA, *subject = NULL, **eku = NULL, *oid, *id = NULL;

  	char *profile = NULL, *issuer = NULL, kustring[16];

+ 	char *ms_template_spec = NULL;

  	char **principal = NULL, **dns = NULL, **email = NULL, **ipaddr = NULL;

  	char *key_owner = NULL, *key_perms = NULL;

  	char *cert_owner = NULL, *cert_perms = NULL;
@@ -789,6 +790,7 @@ 

  		{"ca", 'c', POPT_ARG_STRING, &ca, 0, _("use the specified CA configuration rather than the default"), HELP_TYPE_NAME},

  #endif

  		{"profile", 'T', POPT_ARG_STRING, NULL, 'T', _("ask the CA to process the request using the named profile or template"), HELP_TYPE_NAME},

+ 		{"ms-template-spec", 0, POPT_ARG_STRING, NULL, 'Y', _("include V2 template specifier in CSR (format: OID:MAJOR-VERSION[:MINOR-VERSION])"), HELP_TYPE_NAME},

  		{"issuer", 'X', POPT_ARG_STRING, NULL, 'X', _("ask the CA to process the request using the named issuer"), HELP_TYPE_NAME},

  		{"subject-name", 'N', POPT_ARG_STRING, NULL, 'N', _("set requested subject name (default: CN=<hostname>)"), HELP_TYPE_SUBJECT},

  		{"key-usage", 'u', POPT_ARG_STRING, NULL, 'u', _("set requested key usage value"), HELP_TYPE_KU},
@@ -919,6 +921,9 @@ 

  		case 'T':

  			profile = talloc_strdup(globals.tctx, poptarg);

  			break;

+ 		case 'Y':

+ 			ms_template_spec = talloc_strdup(globals.tctx, poptarg);

+ 			break;

  		case 'X':

  			issuer = talloc_strdup(globals.tctx, poptarg);

  			break;
@@ -1362,6 +1367,13 @@ 

  		params[i] = &param[i];

  		i++;

  	}

+ 	if (ms_template_spec != NULL) {

+ 		param[i].key = CM_DBUS_PROP_TEMPLATE_MS_CERTIFICATE_TEMPLATE;

+ 		param[i].value_type = cm_tdbusm_dict_s;

+ 		param[i].value.s = ms_template_spec;

+ 		params[i] = &param[i];

+ 		i++;

+ 	}

  	if (issuer != NULL) {

  		param[i].key = CM_DBUS_PROP_TEMPLATE_ISSUER;

  		param[i].value_type = cm_tdbusm_dict_s;
@@ -1561,6 +1573,7 @@ 

  		  char *pin, char *pinfile,

  		  char *cpass, char *cpassfile,

  		  char *ca, char *profile, char *issuer,

+ 		  char *ms_template_spec,

  		  char *precommand, char *postcommand,

  		  char **anchor_dbs, char **anchor_files,

  		  int is_ca, int path_length,
@@ -1735,6 +1748,13 @@ 

  		params[i] = &param[i];

  		i++;

  	}

+ 	if (ms_template_spec != NULL) {

+ 		param[i].key = CM_DBUS_PROP_TEMPLATE_MS_CERTIFICATE_TEMPLATE;

+ 		param[i].value_type = cm_tdbusm_dict_s;

+ 		param[i].value.s = ms_template_spec;

+ 		params[i] = &param[i];

+ 		i++;

+ 	}

  	if (issuer != NULL) {

  		param[i].key = CM_DBUS_PROP_TEMPLATE_ISSUER;

  		param[i].value_type = cm_tdbusm_dict_s;
@@ -1825,6 +1845,7 @@ 

  	char *id = NULL, *new_id = NULL, *new_request;

  	char *keyfile = NULL, *certfile = NULL, *ca = DEFAULT_CA;

  	char *profile = NULL, *issuer = NULL;

+ 	char *ms_template_spec = NULL;

  	char *pin = NULL, *pinfile = NULL, *cpass = NULL, *cpassfile = NULL;

  	char *key_owner = NULL, *key_perms = NULL;

  	char *cert_owner = NULL, *cert_perms = NULL;
@@ -1866,6 +1887,7 @@ 

  		{"ca", 'c', POPT_ARG_STRING, &ca, 0, _("use the specified CA configuration rather than the default"), HELP_TYPE_NAME},

  #endif

  		{"profile", 'T', POPT_ARG_STRING, NULL, 'T', _("ask the CA to process the request using the named profile or template"), HELP_TYPE_NAME},

+ 		{"ms-template-spec", 0, POPT_ARG_STRING, NULL, 'Y', _("include V2 template specifier in CSR (format: OID:MAJOR-VERSION[:MINOR-VERSION])"), HELP_TYPE_NAME},

  		{"issuer", 'X', POPT_ARG_STRING, NULL, 'X', _("ask the CA to process the request using the named issuer"), HELP_TYPE_NAME},

  		{"key-usage", 'u', POPT_ARG_STRING, NULL, 'u', _("override requested key usage value"), HELP_TYPE_KU},

  		{"extended-key-usage", 'U', POPT_ARG_STRING, NULL, 'U', _("override requested extended key usage OID"), HELP_TYPE_EKU},
@@ -1971,6 +1993,9 @@ 

  		case 'T':

  			profile = talloc_strdup(globals.tctx, poptarg);

  			break;

+ 		case 'Y':

+ 			ms_template_spec = talloc_strdup(globals.tctx, poptarg);

+ 			break;

  		case 'X':

  			issuer = talloc_strdup(globals.tctx, poptarg);

  			break;
@@ -2409,6 +2434,7 @@ 

  						 pin, pinfile,

  						 cpass, cpassfile,

  						 ca, profile, issuer,

+ 						 ms_template_spec,

  						 precommand, postcommand,

  						 anchor_dbs, anchor_files,

  						 is_ca, path_length,
@@ -2485,6 +2511,7 @@ 

  	char *subject = NULL, **eku = NULL, *oid = NULL;

  	char **principal = NULL, **dns = NULL, **email = NULL, **ipaddr = NULL;

  	char *profile = NULL, *issuer = NULL, kustring[16];

+ 	char *ms_template_spec = NULL;

  	char *key_owner = NULL, *key_perms = NULL;

  	char *cert_owner = NULL, *cert_perms = NULL;

  	char *keytype = NULL;
@@ -2522,6 +2549,7 @@ 

  		{"ca", 'c', POPT_ARG_STRING, &ca, 0, _("use the specified CA configuration rather than the current one"), HELP_TYPE_NAME},

  #endif

  		{"profile", 'T', POPT_ARG_STRING, NULL, 'T', _("ask the CA to process the request using the named profile or template"), HELP_TYPE_NAME},

+ 		{"ms-template-spec", 0, POPT_ARG_STRING, NULL, 'Y', _("include V2 template specifier in CSR (format: OID:MAJOR-VERSION[:MINOR-VERSION])"), HELP_TYPE_NAME},

  		{"issuer", 'X', POPT_ARG_STRING, NULL, 'X', _("ask the CA to process the request using the named issuer"), HELP_TYPE_NAME},

  		{"subject-name", 'N', POPT_ARG_STRING, NULL, 'N', _("set requested subject name (default: CN=<hostname>)"), HELP_TYPE_SUBJECT},

  		{"key-usage", 'u', POPT_ARG_STRING, NULL, 'u', _("set requested key usage value"), HELP_TYPE_KU},
@@ -2600,6 +2628,9 @@ 

  		case 'T':

  			profile = talloc_strdup(globals.tctx, poptarg);

  			break;

+ 		case 'Y':

+ 			ms_template_spec = talloc_strdup(globals.tctx, poptarg);

+ 			break;

  		case 'X':

  			issuer = talloc_strdup(globals.tctx, poptarg);

  			break;
@@ -2975,6 +3006,13 @@ 

  		params[i] = &param[i];

  		i++;

  	}

+ 	if (ms_template_spec != NULL) {

+ 		param[i].key = CM_DBUS_PROP_TEMPLATE_MS_CERTIFICATE_TEMPLATE;

+ 		param[i].value_type = cm_tdbusm_dict_s;

+ 		param[i].value.s = ms_template_spec;

+ 		params[i] = &param[i];

+ 		i++;

+ 	}

  	if (issuer != NULL) {

  		param[i].key = CM_DBUS_PROP_TEMPLATE_ISSUER;

  		param[i].value_type = cm_tdbusm_dict_s;
@@ -4816,6 +4854,8 @@ 

  		N_("  -c CA		use the specified CA rather than the default\n"),

  #endif

  		N_("  -T PROFILE	ask the CA to process the request using the named profile or template\n"),

+ 		N_("  --ms-template-spec SPEC\n"),

+ 		N_("	 include V2 template specifier in CSR (format: OID:MAJOR-VERSION[:MINOR-VERSION])\n"),

  		N_("  -X ISSUER	ask the CA to process the request using the named issuer\n"),

  		N_("* Parameters for the signing request:\n"),

  		N_("  -N NAME	set requested subject name (default: CN=<hostname>)\n"),
@@ -4865,6 +4905,8 @@ 

  		N_("  -c CA		use the specified CA rather than the default\n"),

  #endif

  		N_("  -T PROFILE	ask the CA to process the request using the named profile or template\n"),

+ 		N_("  --ms-template-spec SPEC\n"),

+ 		N_("	 include V2 template specifier in CSR (format: OID:MAJOR-VERSION[:MINOR-VERSION])\n"),

  		N_("  -X ISSUER	ask the CA to process the request using the named issuer\n"),

  		N_("* Parameters for the signing request at renewal time:\n"),

  		N_("  -U EXTUSAGE	override requested extended key usage OID\n"),
@@ -4944,6 +4986,8 @@ 

  		N_("  -c CA		use the specified CA rather than the current one\n"),

  #endif

  		N_("  -T PROFILE	ask the CA to process the request using the named profile or template\n"),

+ 		N_("  --ms-template-spec SPEC\n"),

+ 		N_("	 include V2 template specifier in CSR (format: OID:MAJOR-VERSION[:MINOR-VERSION])\n"),

  		N_("  -X ISSUER	ask the CA to process the request using the named issuer\n"),

  		N_("* Bus options:\n"),

  		N_("  -S		connect to the certmonger service on the system bus\n"),
@@ -4992,6 +5036,8 @@ 

  		N_("  -c CA		use the specified CA rather than the current one\n"),

  #endif

  		N_("  -T PROFILE	ask the CA to process the request using the named profile or template\n"),

+ 		N_("  --ms-template-spec SPEC\n"),

+ 		N_("	 include V2 template specifier in CSR (format: OID:MAJOR-VERSION[:MINOR-VERSION])\n"),

  		N_("  -X ISSUER	ask the CA to process the request using the named issuer\n"),

  		N_("  -G TYPE	type of new key to be generated\n"),

  		N_("  -g SIZE	size of new key to be generated\n"),

file modified
+10
@@ -145,6 +145,7 @@ 

  	cm_store_entry_field_template_ns_comment,

  	cm_store_entry_field_template_profile,

  	cm_store_entry_field_template_issuer,

+ 	cm_store_entry_field_template_certificate_template,

  	cm_store_entry_field_template_no_ocsp_check,

  	cm_store_entry_field_template_ns_certtype,

  
@@ -320,6 +321,7 @@ 

  	{cm_store_entry_field_template_profile, "template_profile"}, /* right */

  	{cm_store_entry_field_template_profile, "ca_profile"}, /* wrong */

  	{cm_store_entry_field_template_issuer, "template_issuer"},

+ 	{cm_store_entry_field_template_certificate_template, "template_certificate_template"},

  	{cm_store_entry_field_template_no_ocsp_check, "template_no_ocsp_check"},

  	{cm_store_entry_field_template_ns_certtype, "template_ns_certtype"},

  
@@ -1208,6 +1210,9 @@ 

  			case cm_store_entry_field_template_profile:

  				ret->cm_template_profile = free_if_empty(p);

  				break;

+ 			case cm_store_entry_field_template_certificate_template:

+ 				ret->cm_template_certificate_template = free_if_empty(p);

+ 				break;

  			case cm_store_entry_field_template_issuer:

  				ret->cm_template_issuer = free_if_empty(p);

  				break;
@@ -1454,6 +1459,7 @@ 

  			case cm_store_entry_field_template_ocsp_location:

  			case cm_store_entry_field_template_ns_comment:

  			case cm_store_entry_field_template_profile:

+ 			case cm_store_entry_field_template_certificate_template:

  			case cm_store_entry_field_template_issuer:

  			case cm_store_entry_field_template_no_ocsp_check:

  			case cm_store_entry_field_template_ns_certtype:
@@ -2063,6 +2069,8 @@ 

  				entry->cm_template_no_ocsp_check ? 1 : 0);

  	cm_store_file_write_str(fp, cm_store_entry_field_template_ns_certtype,

  				entry->cm_template_ns_certtype);

+ 	cm_store_file_write_str(fp, cm_store_entry_field_template_certificate_template,

+ 				entry->cm_template_certificate_template);

  

  	cm_store_file_write_str(fp, cm_store_entry_field_challenge_password,

  				entry->cm_template_challenge_password);
@@ -2824,6 +2832,8 @@ 

  	ret->cm_template_profile = cm_store_maybe_strdup(ret, entry->cm_template_profile);

  	ret->cm_template_issuer = cm_store_maybe_strdup(ret, entry->cm_template_issuer);

  	ret->cm_template_no_ocsp_check = entry->cm_template_no_ocsp_check;

+ 	ret->cm_template_certificate_template =

+ 		cm_store_maybe_strdup(ret, entry->cm_template_certificate_template);

  	ret->cm_template_ns_certtype = cm_store_maybe_strdup(ret,

  							     entry->cm_template_ns_certtype);

  

file modified
+1
@@ -144,6 +144,7 @@ 

  	char *cm_template_profile;

  	char *cm_template_issuer;

  	char *cm_template_ns_certtype;

+ 	char *cm_template_certificate_template;

  	unsigned int cm_template_no_ocsp_check: 1;

  	/* A challenge password, which may be included (in cleartext form!) in

  	 * a CSR. */

file modified
+1
@@ -110,6 +110,7 @@ 

  #define CM_DBUS_PROP_TEMPLATE_PROFILE "template-profile"

  #define CM_DBUS_PROP_TEMPLATE_ISSUER "template-issuer"

  #define CM_DBUS_PROP_TEMPLATE_NS_CERTTYPE "template-ns-certtype"

+ #define CM_DBUS_PROP_TEMPLATE_MS_CERTIFICATE_TEMPLATE "template-ms-certificate-template"

  #define CM_DBUS_SIGNAL_REQUEST_CERT_SAVED "SavedCertificate"

  #define CM_DBUS_PROP_CA_PRESAVE_COMMAND "ca-presave-command"

  #define CM_DBUS_PROP_CA_PRESAVE_UID "ca-presave-uid"

file modified
+49 -1
@@ -32,6 +32,7 @@ 

  

  #include "log.h"

  #include "cm.h"

+ #include "certext.h"

  #include "prefs.h"

  #include "store.h"

  #include "store-int.h"
@@ -1569,6 +1570,25 @@ 

  							     param->value.s);

  	}

  	param = cm_tdbusm_find_dict_entry(d,

+ 					  CM_DBUS_PROP_TEMPLATE_MS_CERTIFICATE_TEMPLATE,

+ 					  cm_tdbusm_dict_s);

+ 	if (param != NULL) {

+ 		if (param->value.s != NULL

+ 		    && strlen(param->value.s) > 0

+ 		    && !cm_ms_template_valid(param->value.s)) {

+ 			cm_log(1, "Invalid V2 certificate template specifier: %s", param->value.s);

+ 			ret = send_internal_base_bad_arg_error(

+ 				conn, msg,

+ 				_("Invalid V2 certificate template specifier: %s"),

+ 				param->value.s,

+ 				CM_DBUS_PROP_TEMPLATE_MS_CERTIFICATE_TEMPLATE);

+ 			talloc_free(parent);

+ 			return ret;

+ 		}

+ 		new_entry->cm_template_certificate_template = maybe_strdup(new_entry,

+ 									   param->value.s);

+ 	}

+ 	param = cm_tdbusm_find_dict_entry(d,

  					  CM_DBUS_PROP_TEMPLATE_CHALLENGE_PASSWORD,

  					  cm_tdbusm_dict_s);

  	if ((param != NULL) &&
@@ -3359,6 +3379,26 @@ 

  				}

  			} else

  			if ((param->value_type == cm_tdbusm_dict_s) &&

+ 			    (strcasecmp(param->key, CM_DBUS_PROP_TEMPLATE_MS_CERTIFICATE_TEMPLATE) == 0)) {

+ 				if (param->value.s != NULL

+ 				    && strlen(param->value.s) > 0

+ 				    && !cm_ms_template_valid(param->value.s)) {

+ 					cm_log(1, "Invalid V2 certificate template specifier: %s", param->value.s);

+ 					return send_internal_base_bad_arg_error(

+ 						conn, msg,

+ 						_("Invalid V2 certificate template specifier: %s"),

+ 						param->value.s,

+ 						CM_DBUS_PROP_TEMPLATE_MS_CERTIFICATE_TEMPLATE);

+ 				}

+ 				talloc_free(entry->cm_template_certificate_template);

+ 				entry->cm_template_certificate_template =

+ 					maybe_strdup(entry, param->value.s);

+ 				if (n_propname + 2 < sizeof(propname) / sizeof(propname[0])) {

+ 					propname[n_propname++] =

+ 						CM_DBUS_PROP_TEMPLATE_MS_CERTIFICATE_TEMPLATE;

+ 				}

+ 			} else

+ 			if ((param->value_type == cm_tdbusm_dict_s) &&

  			    (strcasecmp(param->key, CM_DBUS_PROP_TEMPLATE_CHALLENGE_PASSWORD) == 0)) {

  				talloc_free(entry->cm_template_challenge_password);

  				entry->cm_template_challenge_password = maybe_strdup(entry,
@@ -6773,6 +6813,14 @@ 

  								       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,

  								       NULL),

  				     make_interface_item(cm_tdbush_interface_property,

+ 							 make_property(CM_DBUS_PROP_TEMPLATE_MS_CERTIFICATE_TEMPLATE,

+ 								       cm_tdbush_property_string,

+ 								       cm_tdbush_property_readwrite,

+ 								       cm_tdbush_property_char_p,

+ 								       offsetof(struct cm_store_entry, cm_template_certificate_template),

+ 								       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,

+ 								       NULL),

+ 				     make_interface_item(cm_tdbush_interface_property,

  							 make_property(CM_DBUS_PROP_TEMPLATE_NS_CERTTYPE,

  								       cm_tdbush_property_string,

  								       cm_tdbush_property_readwrite,
@@ -7217,7 +7265,7 @@ 

  				     make_interface_item(cm_tdbush_interface_signal,

  							 make_signal(CM_DBUS_SIGNAL_REQUEST_CERT_SAVED,

  								     NULL),

- 							 NULL))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))));

+ 							 NULL)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))));

  	}

  	return ret;

  }

@@ -330,6 +330,7 @@ 

    <property name="template-ns-comment" type="s" access="readwrite"/>

    <property name="template-profile" type="s" access="readwrite"/>

    <property name="template-issuer" type="s" access="readwrite"/>

+   <property name="template-ms-certificate-template" type="s" access="readwrite"/>

    <property name="template-ns-certtype" type="s" access="readwrite"/>

    <property name="template-challenge-password" type="s" access="readwrite"/>

    <property name="template-challenge-password-file" type="s" access="readwrite"/>

@@ -0,0 +1,19 @@ 

+ [key]

+ OK.

+ [csr : bogus oid]

+ extension not present

+ [csr : bogus major version]

+ extension not present

+ [csr : missing major version]

+ extension not present

+ [csr : too many parts]

+ extension not present

+ [csr : oid, major version]

+     0:d=0  hl=2 l=   8 cons: SEQUENCE          

+     2:d=1  hl=2 l=   3 prim: OBJECT            :1.2.3.4

+     7:d=1  hl=2 l=   1 prim: INTEGER           :2A

+ [csr : oid, major version, minor version]

+     0:d=0  hl=2 l=  11 cons: SEQUENCE          

+     2:d=1  hl=2 l=   3 prim: OBJECT            :1.2.3.4

+     7:d=1  hl=2 l=   1 prim: INTEGER           :2A

+    10:d=1  hl=2 l=   1 prim: INTEGER           :11

@@ -0,0 +1,29 @@ 

+ #!/bin/python2

+ 

+ # Given `openssl asn1parse` output of a CSR, look for the V2 Template

+ # extension and output its data if found.  Nonzero exit status if

+ # not found.

+ 

+ import binascii

+ import re

+ import sys

+ 

+ STATE_SEARCH, STATE_FOUND, STATE_DONE = range(3)

+ 

+ state = STATE_SEARCH

+ 

+ for line in sys.stdin:

+     if state == STATE_SEARCH and ':1.3.6.1.4.1.311.21.7' in line:

+         state = STATE_FOUND

+         continue

+ 

+     # look for first OCTET STRING once we're in STATE_FOUND

+     #

+     if state == STATE_FOUND and 'OCTET STRING' in line:

+         result = re.search(r'\[HEX DUMP\]:(\w*)', line)

+         sys.stdout.write(binascii.unhexlify(result.group(1)))

+         state = STATE_DONE

+         break

+ 

+ if state != STATE_DONE:

+     sys.exit(1)

@@ -0,0 +1,54 @@ 

+ #!/bin/bash -e

+ 

+ srcdir=$PWD

+ cd $tmpdir

+ 

+ mkconfig() {

+ 	cat > request <<- EOF

+ 	key_storage_type=FILE

+ 	key_storage_location=$tmpdir/key

+ 	cert_storage_type=FILE

+ 	cert_storage_location=$tmpdir/cert

+ 	template_subject=CN=MS V2 Certificate Template test

+ 	EOF

+ }

+ 

+ echo "[key]"

+ mkconfig

+ $toolsdir/keygen request

+ 

+ echo "[csr : bogus oid]"

+ mkconfig

+ echo "template_certificate_template=NotAnOid:42" >> request

+ $toolsdir/csrgen request | openssl asn1parse \

+ 	| $srcdir/extract-extdata.py || echo "extension not present"

+ 

+ echo "[csr : bogus major version]"

+ mkconfig

+ echo "template_certificate_template=1.2.3.4:wat" >> request

+ $toolsdir/csrgen request | openssl asn1parse \

+ 	| $srcdir/extract-extdata.py || echo "extension not present"

+ 

+ echo "[csr : missing major version]"

+ mkconfig

+ echo "template_certificate_template=1.2.3.4" >> request

+ $toolsdir/csrgen request | openssl asn1parse \

+ 	| $srcdir/extract-extdata.py || echo "extension not present"

+ 

+ echo "[csr : too many parts]"

+ mkconfig

+ echo "template_certificate_template=1.2.3.4:1:1:1" >> request

+ $toolsdir/csrgen request | openssl asn1parse \

+ 	| $srcdir/extract-extdata.py || echo "extension not present"

+ 

+ echo "[csr : oid, major version]"

+ mkconfig

+ echo "template_certificate_template=1.2.3.4:42" >> request

+ $toolsdir/csrgen request | openssl asn1parse \

+ 	| $srcdir/extract-extdata.py | openssl asn1parse -inform DER

+ 

+ echo "[csr : oid, major version, minor version]"

+ mkconfig

+ echo "template_certificate_template=1.2.3.4:42:17" >> request

+ $toolsdir/csrgen request | openssl asn1parse \

+ 	| $srcdir/extract-extdata.py | openssl asn1parse -inform DER

file modified
+9 -3
@@ -125,7 +125,9 @@ 

  	036-getcert/actual.out \

  	036-getcert/actual.err \

  	037-rekey2/actual.out \

- 	037-rekey2/actual.err

+ 	037-rekey2/actual.err \

+ 	038-ms-v2-template/actual.out \

+ 	038-ms-v2-template/actual.err

  EXTRA_DIST = \

  	run-tests.sh functions certmonger.conf tools/cachain.sh \

  	001-keyiread/run.sh \
@@ -344,7 +346,10 @@ 

  	036-getcert/expected.out \

  	036-getcert/run.sh \

  	037-rekey2/expected.out \

- 	037-rekey2/run.sh

+ 	037-rekey2/run.sh \

+ 	038-ms-v2-template/expected.out \

+ 	038-ms-v2-template/extract-extdata.py \

+ 	038-ms-v2-template/run.sh

  

  subdirs = \

  	001-keyiread \
@@ -386,7 +391,8 @@ 

  	034-perms \

  	035-json \

  	036-getcert \

- 	037-rekey2

+ 	037-rekey2 \

+ 	038-ms-v2-template

  

  if HAVE_DBM_NSSDB

  subdirs += \

rebased

3 years ago

rebased

3 years ago

Did you mean to include this?

nit: should you check for NULL?

By returning just TRUE/FALSE here (via NULL) users could have a hard time figuring out where their formatting is bad.

Is this a use-after-free? result is the return value of cm_certext_build_certificate_template() which is created via return SECITEM_ArenaDupItem(arena, &encoded). The arena is freed before result is compared.

There should probably also be tests for each of the validation cases as well as a passing case.

nope, we're only comparing that the pointer was not-null. The memory pointed to is freed, but we don't need to read it - we only need to know that it was not null (i.e. successfully parsed, therefore input is valid)

I think the additional complexity to get an explanation to the user is not worth it. It's an esoteric feature, and I think it's documented well enough. The immediate use case is for IPA which does its own checking (and if the input is invalid, explaining what's wrong).

4 new commits added

  • MS cert template: validate argument
  • MS cert template: add option to command line programs
  • MS cert template: add template extension to CSR
  • MS cert template: add D-Bus property and storage
3 years ago

1 new commit added

  • MS cert template: add tests
3 years ago

But this is a certmonger feature and anyone else can do things, get a failure and have no idea what is wrong. Also, documented where?

But this is a certmonger feature and anyone else can do things, get a failure and have no idea what is wrong. Also, documented where?

The expected format is documented in man pages.

I also updated api.txt to describe the expected format.

rebased

3 years ago

@rcritten any further comments? How badly do you want a specific error string explaining problems in the template specifier string input? :)

It's fine. We can address it if it comes up. I needed to do some more functional testing. I tested with:

# ipa-getcert request -f /etc/pki/tls/certs/test.pem -k /etc/pki/tls/private/test.pem --ms-template-spec=1.3.6.1.4.1.311.21.8.8950086.10656446.2706058.12775672.480128.147.7130143.4405632:1 -K test/`hostname`

The CSR looks reasonably ok (I didn't bother to decode the value) via openssl req:

    Requested Extensions:
        X509v3 Subject Alternative Name: 
            othername:<unsupported>, othername:<unsupported>
        X509v3 Basic Constraints: critical
            CA:FALSE
        X509v3 Subject Key Identifier: 
            F5:82:2E:CB:45:D5:B1:E3:F1:0B:67:4A:C6:59:10:93:A6:DA:A0:77
        1.3.6.1.4.1.311.21.7: 
            0+.&+.....7.....F...>...

It its a bit difficult to understand where these OIDs come from but given it's MS I'll take it for granted that those admins will know what to pass.

So ACK.

Pull-Request has been merged by rcritten

3 years ago

On Wed, Aug 30, 2017 at 05:31:52PM +0000, Rob Crittenden wrote:

rcritten commented on the pull-request: Implement support for MS V2 template extension that you are following:
``
It's fine. We can address it if it comes up. I needed to do some more functional testing. I tested with:

# ipa-getcert request -f /etc/pki/tls/certs/test.pem -k /etc/pki/tls/private/test.pem --ms-template-spec=1.3.6.1.4.1.311.21.8.8950086.10656446.2706058.12775672.480128.147.7130143.4405632:1 -K test/`hostname`

The CSR looks reasonably ok (I didn't bother to decode the value) via openssl req:

    Requested Extensions:
        X509v3 Subject Alternative Name: 
            othername:<unsupported>, othername:<unsupported>
        X509v3 Basic Constraints: critical
            CA:FALSE
        X509v3 Subject Key Identifier: 
            F5:82:2E:CB:45:D5:B1:E3:F1:0B:67:4A:C6:59:10:93:A6:DA:A0:77
        1.3.6.1.4.1.311.21.7: 
            0+.&+.....7.....F...>...

It its a bit difficult to understand where these OIDs come from but given it's MS I'll take it for granted that those admins will know what to pass.

So ACK.
``
The OIDs are identifiers of certificate templates in an AD-CS
installation.

When submitting a CSR to AD-CS, the template specifier (either the
V1 string based one, or the V2 OID-based one) get read, and this
selects the template (profile) to use for issuing the cert.

It's actually an error if you try to submit a CSR that does have one
of these extensions!