bx509d: Allow requesting longer cert lifetimes
Add a `lifetime=NUMunit` query parameter. Also add a krb5.conf parameter to indicate whether this is allowed. We already have a max lifetime configuration parameter.
This commit is contained in:
		
							
								
								
									
										41
									
								
								kdc/bx509d.8
									
									
									
									
									
								
							
							
						
						
									
										41
									
								
								kdc/bx509d.8
									
									
									
									
									
								
							| @@ -113,6 +113,45 @@ Uses a thread per-client instead of as many threads as there are CPUs. | ||||
| .Xc | ||||
| verbose | ||||
| .El | ||||
| .Sh API | ||||
| This service provides an HTTP-based Certification Authority (CA). | ||||
| The protocol consists of a | ||||
| .Ar GET | ||||
| of | ||||
| .Ar /bx509 | ||||
| with the base-63 encoding of a DER encoding of a PKCS#10 | ||||
| .Ar CertificationRequest | ||||
| (Certificate Signing Request, or CSR) in a | ||||
| .Ar csr | ||||
| required query parameter. | ||||
| In a successful query, the response body will contain a PEM | ||||
| encoded end entity certificate and certification chain. | ||||
| .Pp | ||||
| Authentication is required. | ||||
| Unauthenticated requests will elicit a 401 response. | ||||
| .Pp | ||||
| Subject Alternative Names (SANs) and Extended Key Usage values | ||||
| may be requested, both in-band in the CSR as a requested | ||||
| extensions attribute, and/or via optional query parameters. | ||||
| .Pp | ||||
| Supported query parameters (separated by ampersands) | ||||
| .Bl -tag -width Ds -offset indent | ||||
| .It Li csr = Va <base64-encoded-DER-encoded-CSR> | ||||
| .It Li dNSName = Va <hostname> | ||||
| .It Li rfc822Name = Va <email-address> | ||||
| .It Li xMPPName = Va <XMPP-address> | ||||
| .It Li krb5PrincipalName = Va <Kerberos-principal-name> | ||||
| .It Li ms-upn = Va <UPN> | ||||
| .It Li eku = Va <OID> | ||||
| .It Li lifetime = Va <lifetime> | ||||
| .El | ||||
| .Pp | ||||
| More than one name or EKU may be requested. | ||||
| .Pp | ||||
| Certificate lifetimes are expressed as a decimal number and | ||||
| an optional unit (which defaults to | ||||
| .Dq day | ||||
| ). | ||||
| .Sh ENVIRONMENT | ||||
| .Bl -tag -width Ds | ||||
| .It Ev KRB5_CONFIG | ||||
| @@ -122,6 +161,8 @@ the default being | ||||
| .Pa /etc/krb5.conf . | ||||
| .El | ||||
| .Sh FILES | ||||
| Configuration parameters are specified in | ||||
| .Ar /etc/krb5.conf . | ||||
| .Bl -tag -width Ds | ||||
| .It Pa /etc/krb5.conf | ||||
| .El | ||||
|   | ||||
							
								
								
									
										11
									
								
								kdc/bx509d.c
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								kdc/bx509d.c
									
									
									
									
									
								
							| @@ -117,6 +117,7 @@ typedef struct bx509_request_desc { | ||||
|  | ||||
|     struct MHD_Connection *connection; | ||||
|     krb5_times token_times; | ||||
|     time_t req_life; | ||||
|     hx509_request req; | ||||
|     const char *target; | ||||
|     const char *redir; | ||||
| @@ -667,6 +668,8 @@ bx509_param_cb(void *d, | ||||
|     } else if (strcmp(key, "csr") == 0 && val) { | ||||
|         heim_audit_addkv((heim_svc_req_desc)a->r, 0, "requested_csr", "true"); | ||||
|         a->ret = 0; /* Handled upstairs */ | ||||
|     } else if (strcmp(key, "lifetime") == 0 && val) { | ||||
|         a->r->req_life = parse_time(val, "day"); | ||||
|     } else { | ||||
|         /* Produce error for unknown params */ | ||||
|         heim_audit_addkv((heim_svc_req_desc)a->r, 0, "requested_unknown", "true"); | ||||
| @@ -798,7 +801,8 @@ do_CA(struct bx509_request_desc *r, const char *csr) | ||||
|  | ||||
|     /* Issue the certificate */ | ||||
|     ret = kdc_issue_certificate(r->context, "bx509", logfac, r->req, p, | ||||
|                                 &r->token_times, 1 /* send_chain */, &certs); | ||||
|                                 &r->token_times, r->req_life, | ||||
|                                 1 /* send_chain */, &certs); | ||||
|     krb5_free_principal(r->context, p); | ||||
|     if (ret) { | ||||
|         if (ret == KRB5KDC_ERR_POLICY || ret == EACCES) | ||||
| @@ -872,6 +876,7 @@ set_req_desc(struct MHD_Connection *connection, | ||||
|     r->cname = NULL; | ||||
|     r->addr = NULL; | ||||
|     r->req = NULL; | ||||
|     r->req_life = 0; | ||||
|     r->kv = heim_array_create(); | ||||
|     ci = MHD_get_connection_info(connection, | ||||
|                                  MHD_CONNECTION_INFO_CLIENT_ADDRESS); | ||||
| @@ -1268,8 +1273,8 @@ bnegotiate_do_CA(struct bx509_request_desc *r) | ||||
|     /* Issue the certificate */ | ||||
|     if (ret == 0) | ||||
|         ret = kdc_issue_certificate(r->context, "bx509", logfac, req, p, | ||||
|                                     &r->token_times, 1 /* send_chain */, | ||||
|                                     &certs); | ||||
|                                     &r->token_times, 0, | ||||
|                                     1 /* send_chain */, &certs); | ||||
|     krb5_free_principal(r->context, p); | ||||
|     hx509_request_free(&req); | ||||
|     p = NULL; | ||||
|   | ||||
							
								
								
									
										5
									
								
								kdc/ca.c
									
									
									
									
									
								
							
							
						
						
									
										5
									
								
								kdc/ca.c
									
									
									
									
									
								
							| @@ -104,6 +104,7 @@ kdc_issue_certificate(krb5_context context, | ||||
|                       hx509_request req, | ||||
|                       krb5_principal cprinc, | ||||
|                       krb5_times *auth_times, | ||||
|                       time_t req_life, | ||||
|                       int send_chain, | ||||
|                       hx509_certs *out) | ||||
| { | ||||
| @@ -122,7 +123,9 @@ kdc_issue_certificate(krb5_context context, | ||||
|                                           (const heim_config_binding *)cf, | ||||
|                                           logf, req, &cprinc2, | ||||
|                                           auth_times->starttime, | ||||
|                                           auth_times->endtime, send_chain, | ||||
|                                           auth_times->endtime, | ||||
|                                           req_life, | ||||
|                                           send_chain, | ||||
|                                           out); | ||||
|     if (ret == EACCES) | ||||
|         ret = KRB5KDC_ERR_POLICY; | ||||
|   | ||||
| @@ -1005,8 +1005,8 @@ _kdc_do_kx509(kx509_req_context r) | ||||
|     krb5_data_zero(rep.certificate); | ||||
|     krb5_ticket_get_times(r->context, ticket, &r->ticket_times); | ||||
|     ret = kdc_issue_certificate(r->context, r->config->app, r->logf, r->csr, | ||||
|                                 cprincipal, &r->ticket_times, r->send_chain, | ||||
|                                 &certs); | ||||
|                                 cprincipal, &r->ticket_times, 0 /*req_life*/, | ||||
|                                 r->send_chain, &certs); | ||||
|     if (ret) { | ||||
|         int level = 1; | ||||
| 	const char *msg = krb5_get_error_message(r->context, ret); | ||||
|   | ||||
| @@ -2,12 +2,15 @@ | ||||
|  | ||||
| static int authorized_flag; | ||||
| static int help_flag; | ||||
| static char *lifetime_string; | ||||
| static const char *app_string = "kdc"; | ||||
| static int version_flag; | ||||
|  | ||||
| struct getargs args[] = { | ||||
|     {   "authorized",   'A',    arg_flag,   &authorized_flag, | ||||
|         "Assume CSR is authorized", NULL }, | ||||
|     {   "lifetime",     'l',    arg_string, &lifetime_string, | ||||
|         "Certificate lifetime desired", "TIME" }, | ||||
|     {   "help",         'h',    arg_flag,   &help_flag, | ||||
|         "Print usage message", NULL }, | ||||
|     {   "app",          'a',    arg_string, &app_string, | ||||
| @@ -78,6 +81,7 @@ main(int argc, char **argv) | ||||
|     hx509_certs certs = NULL; | ||||
|     const char *argv0 = argv[0]; | ||||
|     const char *out = "MEMORY:junk-it"; | ||||
|     time_t req_life = 0; | ||||
|     int optidx = 0; | ||||
|  | ||||
|     setprogname(argv[0]); | ||||
| @@ -143,8 +147,9 @@ main(int argc, char **argv) | ||||
|     memset(&t, 0, sizeof(t)); | ||||
|     t.starttime = time(NULL); | ||||
|     t.endtime = t.starttime + 3600; | ||||
|     if ((ret = kdc_issue_certificate(context, app_string, logf, req, p, &t, 1, | ||||
|                                      &certs))) | ||||
|     req_life = lifetime_string ? parse_time(lifetime_string, "day") : 0; | ||||
|     if ((ret = kdc_issue_certificate(context, app_string, logf, req, p, &t, | ||||
|                                      req_life, 1, &certs))) | ||||
|         krb5_err(context, 1, ret, "Certificate issuance failed"); | ||||
|  | ||||
|     if (argv[2]) | ||||
|   | ||||
| @@ -2835,6 +2835,7 @@ enomem: | ||||
| static heim_error_code | ||||
| tbs_set_times(hx509_context context, | ||||
|               const heim_config_binding *cf, | ||||
|               heim_log_facility *logf, | ||||
|               time_t starttime, | ||||
|               time_t endtime, | ||||
|               time_t req_life, | ||||
| @@ -2847,15 +2848,29 @@ tbs_set_times(hx509_context context, | ||||
|     time_t clamp = | ||||
|         heim_config_get_time_default(context->hcontext, cf, 0, | ||||
|                                      "max_cert_lifetime", NULL); | ||||
|     int allow_more = | ||||
|         heim_config_get_bool_default(context->hcontext, cf, FALSE, | ||||
|                                      "allow_extra_lifetime", NULL); | ||||
|  | ||||
|     if (!allow_more && fudge && now + fudge > endtime) | ||||
|         allow_more = 1; | ||||
|  | ||||
|     starttime = starttime ?  starttime : now - 5 * 60; | ||||
|     if (fudge && now + fudge > endtime) | ||||
|         endtime = now + fudge; | ||||
|     if (req_life && req_life < endtime - now) | ||||
|     if (req_life > 0 && req_life < endtime - now) | ||||
|         endtime = now + req_life; | ||||
|     if (clamp && clamp < endtime - now) | ||||
|         endtime = now + clamp; | ||||
|  | ||||
|     if (endtime < now) { | ||||
|         heim_log_msg(context->hcontext, logf, 3, NULL, | ||||
|                      "Endtime would be in the past"); | ||||
|         hx509_set_error_string(context, 0, ERANGE, | ||||
|                                "Endtime would be in the past"); | ||||
|         return ERANGE; | ||||
|     } | ||||
|  | ||||
|     hx509_ca_tbs_set_notAfter(context, tbs, endtime); | ||||
|     hx509_ca_tbs_set_notBefore(context, tbs, starttime); | ||||
|     return 0; | ||||
| @@ -2874,6 +2889,7 @@ _hx509_ca_issue_certificate(hx509_context context, | ||||
|                             KRB5PrincipalName *cprinc, | ||||
|                             time_t starttime, | ||||
|                             time_t endtime, | ||||
|                             time_t req_life, | ||||
|                             int send_chain, | ||||
|                             hx509_certs *out) | ||||
| { | ||||
| @@ -2995,8 +3011,8 @@ _hx509_ca_issue_certificate(hx509_context context, | ||||
|  | ||||
|     /* Work out cert expiration */ | ||||
|     if (ret == 0) | ||||
|         ret = tbs_set_times(context, cf, starttime, endtime, | ||||
|                             0 /* XXX req_life */, tbs); | ||||
|         ret = tbs_set_times(context, cf, logf, starttime, endtime, req_life, | ||||
|                             tbs); | ||||
|  | ||||
|     /* Expand the subjectName template in the TBS using the env */ | ||||
|     if (ret == 0) | ||||
|   | ||||
| @@ -827,9 +827,30 @@ for non-default client and server certificates. | ||||
| and where the parameters are as follows: | ||||
| .Bl -tag -width "xxx" -offset indent | ||||
| .It Li ca = Va file | ||||
| Specifies the PEM credentials for the kx509 certification | ||||
| authority.  If not specified for any specific use-case, then that | ||||
| use-case will be disabled. | ||||
| Specifies the PEM credentials for the kx509 / bx509d certification | ||||
| authority. | ||||
| If not specified for any specific use-case, then that use-case | ||||
| will be disabled. | ||||
| .It Li max_cert_lifetime = Va NUMunit | ||||
| Specifies the maximum certificate lifetime as a decimal number | ||||
| and an optional unit (the default unit is | ||||
| .Dq day | ||||
| ). | ||||
| .It Li force_cert_lifetime = Va NUMunit | ||||
| Specifies a minimum certificate lifetime as a decimal number and | ||||
| an optional unit (the default unit is | ||||
| .Dq day | ||||
| ). | ||||
| .It Li allow_extra_lifetime = Va boolean | ||||
| Indicates whether a client may request longer lifetimes than | ||||
| their authentication credentials. | ||||
| Defaults to false. | ||||
| If a | ||||
| .Li force_cert_lifetime | ||||
| is specified, then | ||||
| .Li allow_extra_lifetime | ||||
| is implicitly forced to | ||||
| .Va true . | ||||
| .It Li require_initial_kca_tickets = Va boolean | ||||
| Specified whether to require that tickets for the | ||||
| .Li kca_service | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Nicolas Williams
					Nicolas Williams