kx509: add time-to-live for kx509 -t option
It's useful to check for having so many seconds left in useful credential lifetime.
This commit is contained in:
		| @@ -270,8 +270,8 @@ command = { | |||||||
| 	option = { | 	option = { | ||||||
| 		long = "test" | 		long = "test" | ||||||
| 		short = "t" | 		short = "t" | ||||||
| 		type = "flag" | 		type = "integer" | ||||||
| 		help = "exit successfully if certificate and private key are in credential cache" | 		help = "check for certificate with at least given time left" | ||||||
| 	} | 	} | ||||||
| 	option = { | 	option = { | ||||||
| 		name = "private-key" | 		name = "private-key" | ||||||
|   | |||||||
| @@ -56,8 +56,8 @@ | |||||||
| .Fl Fl extract | .Fl Fl extract | ||||||
| .Xc | .Xc | ||||||
| .Oc | .Oc | ||||||
| .Oo Fl t \*(Ba Xo | .Oo Fl t Ar time-left \*(Ba Xo | ||||||
| .Fl Fl test | .Fl Fl test= Ns Ar time-left | ||||||
| .Xc | .Xc | ||||||
| .Oc | .Oc | ||||||
| .Oo Fl C Ar PKCS10:filename \*(Ba Xo | .Oo Fl C Ar PKCS10:filename \*(Ba Xo | ||||||
| @@ -89,9 +89,14 @@ Options supported: | |||||||
| .It Fl c Ar cache , Fl Fl cache= Ns Ar cache | .It Fl c Ar cache , Fl Fl cache= Ns Ar cache | ||||||
| credential cache to use (if not given, then the default will be | credential cache to use (if not given, then the default will be | ||||||
| used). | used). | ||||||
| .It Fl t , Fl Fl test | .It Fl t Ar time-left , Fl Fl test= Ns Ar time-left | ||||||
| Test for there being an active and valid certificate in the | Test for there being an active and valid certificate in the | ||||||
| credential cache. | credential cache, with at least | ||||||
|  | .Ar time-left | ||||||
|  | seconds left of valid life.  If given with the | ||||||
|  | .Fl o | ||||||
|  | then the certificates in the hx509 store are tested along with | ||||||
|  | those in the credentials cache (if any). | ||||||
| .It Fl x , Fl Fl extract | .It Fl x , Fl Fl extract | ||||||
| Extract, rather than acquire credentials. | Extract, rather than acquire credentials. | ||||||
| .It Fl s , Fl Fl save | .It Fl s , Fl Fl save | ||||||
|   | |||||||
| @@ -39,14 +39,30 @@ | |||||||
| #include "../lib/krb5/krb5_locl.h" | #include "../lib/krb5/krb5_locl.h" | ||||||
| #include "hx509-private.h" | #include "hx509-private.h" | ||||||
|  |  | ||||||
|  | struct validate_store { | ||||||
|  |     size_t ncerts; | ||||||
|  |     int grace; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | static int | ||||||
|  | validate1(hx509_context hx509ctx, void *d, hx509_cert cert) | ||||||
|  | { | ||||||
|  |     struct validate_store *v = d; | ||||||
|  |  | ||||||
|  |     if (hx509_cert_get_notAfter(cert) < time(NULL) + v->grace) | ||||||
|  |         return HX509_CERT_USED_AFTER_TIME; | ||||||
|  |     v->ncerts++; | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
| static void | static void | ||||||
| validate(krb5_context context, | validate(krb5_context context, | ||||||
|  |          int grace, | ||||||
|          const char *hx509_store, |          const char *hx509_store, | ||||||
|          krb5_data *der_cert, |          krb5_data *der_cert, | ||||||
|          krb5_data *pkcs8_priv_key) |          krb5_data *pkcs8_priv_key) | ||||||
| { | { | ||||||
|     hx509_context hx509ctx = NULL; |     hx509_context hx509ctx = NULL; | ||||||
|     hx509_private_key key = NULL; |  | ||||||
|     hx509_cert cert; |     hx509_cert cert; | ||||||
|     krb5_error_code ret; |     krb5_error_code ret; | ||||||
|  |  | ||||||
| @@ -54,6 +70,9 @@ validate(krb5_context context, | |||||||
|     if (ret) |     if (ret) | ||||||
|         krb5_err(context, 1, ret, "hx509 context init"); |         krb5_err(context, 1, ret, "hx509 context init"); | ||||||
|  |  | ||||||
|  |     if (der_cert->data && pkcs8_priv_key->data) { | ||||||
|  |         hx509_private_key key = NULL; | ||||||
|  |  | ||||||
|         cert = hx509_cert_init_data(hx509ctx, der_cert->data, |         cert = hx509_cert_init_data(hx509ctx, der_cert->data, | ||||||
|                                     der_cert->length, NULL); |                                     der_cert->length, NULL); | ||||||
|         if (cert == NULL) |         if (cert == NULL) | ||||||
| @@ -63,10 +82,32 @@ validate(krb5_context context, | |||||||
|                                       HX509_KEY_FORMAT_PKCS8, &key); |                                       HX509_KEY_FORMAT_PKCS8, &key); | ||||||
|         if (ret) |         if (ret) | ||||||
|             krb5_err(context, 1, ret, "certificate could not be loaded"); |             krb5_err(context, 1, ret, "certificate could not be loaded"); | ||||||
|     if (hx509_cert_get_notAfter(cert) < time(NULL)) |         if (hx509_cert_get_notAfter(cert) < time(NULL) + grace) | ||||||
|             krb5_errx(context, 1, "certificate is expired"); |             krb5_errx(context, 1, "certificate is expired"); | ||||||
|         hx509_private_key_free(&key); |         hx509_private_key_free(&key); | ||||||
|         hx509_cert_free(cert); |         hx509_cert_free(cert); | ||||||
|  |     } | ||||||
|  |     if (hx509_store) { | ||||||
|  |         struct validate_store v; | ||||||
|  |         hx509_certs certs; | ||||||
|  |  | ||||||
|  |         v.ncerts = 0; | ||||||
|  |         v.grace = grace; | ||||||
|  |  | ||||||
|  |         ret = hx509_certs_init(hx509ctx, hx509_store, 0, NULL, &certs); | ||||||
|  |         if (ret) | ||||||
|  |             krb5_err(context, 1, ret, "could not read hx509 store %s", | ||||||
|  |                      hx509_store); | ||||||
|  |         ret = hx509_certs_iter_f(hx509ctx, certs, validate1, &v); | ||||||
|  |         if (ret) | ||||||
|  |             krb5_err(context, 1, ret, "at least one certificate in %s expired", | ||||||
|  |                      hx509_store); | ||||||
|  |         if (!v.ncerts) | ||||||
|  |             krb5_errx(context, 1, "no certificates in %s", hx509_store); | ||||||
|  |  | ||||||
|  |         hx509_certs_free(&certs); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     hx509_context_free(&hx509ctx); |     hx509_context_free(&hx509ctx); | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -124,7 +165,8 @@ store(krb5_context context, | |||||||
|         hx509_store = krb5_config_get_string(context, NULL, "libdefaults", |         hx509_store = krb5_config_get_string(context, NULL, "libdefaults", | ||||||
|                                              "kx509_store", NULL); |                                              "kx509_store", NULL); | ||||||
|         if (hx509_store) { |         if (hx509_store) { | ||||||
|             ret = _krb5_expand_path_tokens(context, hx509_store, 1, &store_exp); |             ret = _krb5_expand_path_tokens(context, hx509_store, 1, | ||||||
|  |                                            &store_exp); | ||||||
|             if (ret) |             if (ret) | ||||||
|                 krb5_err(context, 1, ret, "expanding tokens in default " |                 krb5_err(context, 1, ret, "expanding tokens in default " | ||||||
|                          "hx509 store"); |                          "hx509 store"); | ||||||
| @@ -202,28 +244,32 @@ kx509(struct kx509_options *opt, int argc, char **argv) | |||||||
|     if (opt->save_flag) |     if (opt->save_flag) | ||||||
|         ccout = cc; |         ccout = cc; | ||||||
|  |  | ||||||
|     if (opt->test_flag && |     if (opt->test_integer && | ||||||
|         (opt->extract_flag || opt->csr_string || opt->private_key_string)) |         (opt->extract_flag || opt->csr_string || opt->private_key_string)) | ||||||
|         krb5_errx(context, 1, "--test is exclusive of --extract, --csr, and " |         krb5_errx(context, 1, "--test is exclusive of --extract, --csr, and " | ||||||
|                   "--private-key"); |                   "--private-key"); | ||||||
|  |  | ||||||
|     if (opt->extract_flag && (opt->csr_string || opt->private_key_string)) |     if (opt->extract_flag && (opt->csr_string || opt->private_key_string)) | ||||||
|         krb5_errx(context, 1, "--extract is exclusive of --csr and --private-key"); |         krb5_errx(context, 1, "--extract is exclusive of --csr and " | ||||||
|  |                   "--private-key"); | ||||||
|  |  | ||||||
|     if (opt->test_flag || opt->extract_flag) { |     if (opt->test_integer || opt->extract_flag) { | ||||||
|         krb5_data der_cert, pkcs8_key, chain; |         krb5_data der_cert, pkcs8_key, chain; | ||||||
|  |  | ||||||
|         der_cert.data = pkcs8_key.data = chain.data = NULL; |         der_cert.data = pkcs8_key.data = chain.data = NULL; | ||||||
|         der_cert.length = pkcs8_key.length = chain.length = 0; |         der_cert.length = pkcs8_key.length = chain.length = 0; | ||||||
|         ret = krb5_cc_get_config(context, cc, NULL, "kx509cert", &der_cert); |         ret = krb5_cc_get_config(context, cc, NULL, "kx509cert", &der_cert); | ||||||
|         if (ret == 0) |         if (ret == 0) | ||||||
|             ret = krb5_cc_get_config(context, cc, NULL, "kx509key", &pkcs8_key); |             ret = krb5_cc_get_config(context, cc, NULL, "kx509key", | ||||||
|  |                                      &pkcs8_key); | ||||||
|         if (ret == 0) |         if (ret == 0) | ||||||
|             ret = krb5_cc_get_config(context, cc, NULL, "kx509cert-chain", &chain); |             ret = krb5_cc_get_config(context, cc, NULL, "kx509cert-chain", | ||||||
|  |                                      &chain); | ||||||
|         if (ret) |         if (ret) | ||||||
|             krb5_err(context, 1, ret, "no certificate in credential cache"); |             krb5_err(context, 1, ret, "no certificate in credential cache"); | ||||||
|         if (opt->test_flag) |         if (opt->test_integer) | ||||||
|             validate(context, opt->out_string, &der_cert, &pkcs8_key); |             validate(context, opt->test_integer, opt->out_string, &der_cert, | ||||||
|  |                      &pkcs8_key); | ||||||
|         else |         else | ||||||
|             store(context, opt->out_string, &der_cert, &pkcs8_key, &chain); |             store(context, opt->out_string, &der_cert, &pkcs8_key, &chain); | ||||||
|         krb5_data_free(&pkcs8_key); |         krb5_data_free(&pkcs8_key); | ||||||
| @@ -240,13 +286,15 @@ kx509(struct kx509_options *opt, int argc, char **argv) | |||||||
|         if (ret == 0 && opt->csr_string) |         if (ret == 0 && opt->csr_string) | ||||||
|             set_csr(context, req, opt->csr_string); |             set_csr(context, req, opt->csr_string); | ||||||
|         if (ret == 0 && opt->private_key_string) |         if (ret == 0 && opt->private_key_string) | ||||||
|             ret = krb5_kx509_ctx_set_key(context, req, opt->private_key_string); |             ret = krb5_kx509_ctx_set_key(context, req, | ||||||
|  |                                          opt->private_key_string); | ||||||
|         if (ret) |         if (ret) | ||||||
|             krb5_err(context, 1, ret, "could not setup kx509 request options"); |             krb5_err(context, 1, ret, "could not setup kx509 request options"); | ||||||
|  |  | ||||||
|         ret = krb5_kx509_ext(context, req, cc, opt->out_string, ccout); |         ret = krb5_kx509_ext(context, req, cc, opt->out_string, ccout); | ||||||
|         if (ret) |         if (ret) | ||||||
|             krb5_err(context, 1, ret, "could not acquire certificate with kx509"); |             krb5_err(context, 1, ret, | ||||||
|  |                      "could not acquire certificate with kx509"); | ||||||
|         krb5_kx509_ctx_free(context, &req); |         krb5_kx509_ctx_free(context, &req); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Nicolas Williams
					Nicolas Williams