kx509: Add CSR support
This commit adds support for proof of posession to the kx509 protocol by using PKCS#10 CSRs. This allows conveyance of extReq CSR attributes requesting desired Certificate Extensions.
This commit is contained in:
@@ -17,7 +17,8 @@ man_MANS = \
|
||||
kswitch.1 \
|
||||
kdigest.8 \
|
||||
kgetcred.1 \
|
||||
kimpersonate.8
|
||||
kimpersonate.8 \
|
||||
kx509.1
|
||||
|
||||
bin_PROGRAMS = kinit kdestroy kgetcred heimtools
|
||||
libexec_PROGRAMS = kdigest kimpersonate
|
||||
@@ -45,7 +46,7 @@ heimtools_LDADD = \
|
||||
$(LIB_readline) \
|
||||
$(LIB_hx509)
|
||||
|
||||
dist_heimtools_SOURCES = heimtools.c klist.c kswitch.c copy_cred_cache.c
|
||||
dist_heimtools_SOURCES = heimtools.c klist.c kx509.c kswitch.c copy_cred_cache.c
|
||||
nodist_heimtools_SOURCES = heimtools-commands.c
|
||||
|
||||
$(heimtools_OBJECTS): heimtools-commands.h
|
||||
@@ -94,5 +95,6 @@ EXTRA_DIST = NTMakefile $(man_MANS) \
|
||||
# make sure install-exec-hook doesn't have any commands in Makefile.am.common
|
||||
install-exec-hook:
|
||||
(cd $(DESTDIR)$(bindir) && rm -f klist && $(LN_S) heimtools klist)
|
||||
(cd $(DESTDIR)$(bindir) && rm -f kx509 && $(LN_S) heimtools kx509)
|
||||
(cd $(DESTDIR)$(bindir) && rm -f kswitch && $(LN_S) heimtools kswitch)
|
||||
|
||||
|
@@ -79,6 +79,7 @@ HEIMTOOLS_OBJS = \
|
||||
$(OBJ)\heimtools.obj \
|
||||
$(OBJ)\kswitch.obj \
|
||||
$(OBJ)\klist.obj \
|
||||
$(OBJ)\kx509.obj \
|
||||
$(OBJ)\copy_cred_cache.obj
|
||||
|
||||
HEIMTOOLSLIBS=\
|
||||
|
@@ -114,11 +114,6 @@ command = {
|
||||
type = "flag"
|
||||
help = "Verbose output"
|
||||
}
|
||||
option = {
|
||||
long = "extract-kx509-cert"
|
||||
type = "string"
|
||||
help = "hx509 store for kx509 certificate and private key"
|
||||
}
|
||||
}
|
||||
command = {
|
||||
name = "kgetcred"
|
||||
@@ -245,6 +240,60 @@ command = {
|
||||
help = "Copies credential caches"
|
||||
argument = "[source] destination"
|
||||
}
|
||||
command = {
|
||||
name = "kx509"
|
||||
help = "Acquire or extract certificates"
|
||||
option = {
|
||||
long = "cache"
|
||||
short = "c"
|
||||
type = "string"
|
||||
help = "Kerberos credential cache"
|
||||
}
|
||||
option = {
|
||||
long = "save"
|
||||
short = "s"
|
||||
type = "flag"
|
||||
help = "save the certificate and private key in the Kerberos credential cache"
|
||||
}
|
||||
option = {
|
||||
long = "out"
|
||||
short = "o"
|
||||
type = "string"
|
||||
help = "hx509 store for kx509 certificate and private key"
|
||||
}
|
||||
option = {
|
||||
long = "extract"
|
||||
short = "x"
|
||||
type = "flag"
|
||||
help = "extract certificate and private key from credential cache"
|
||||
}
|
||||
option = {
|
||||
long = "test"
|
||||
short = "t"
|
||||
type = "flag"
|
||||
help = "exit successfully if certificate and private key are in credential cache"
|
||||
}
|
||||
option = {
|
||||
name = "private-key"
|
||||
short = "K"
|
||||
type = "string"
|
||||
help = "hx509 store containing private key"
|
||||
}
|
||||
option = {
|
||||
name = "csr"
|
||||
short = "C"
|
||||
type = "string"
|
||||
help = "file containing DER-encoded PKCS#10 certificate request"
|
||||
}
|
||||
option = {
|
||||
name = "realm"
|
||||
short = "r"
|
||||
type = "string"
|
||||
help = "realm from which to acquire certificate"
|
||||
}
|
||||
min_args = "0"
|
||||
max_args = "0"
|
||||
}
|
||||
command = {
|
||||
name = "help"
|
||||
name = "?"
|
||||
|
@@ -44,8 +44,6 @@
|
||||
.Fl Fl cache= Ns Ar cache
|
||||
.Xc
|
||||
.Oc
|
||||
.Oo Fl Fl extract-kx509-cert= Ns Ar hx509-store
|
||||
.Oc
|
||||
.Op Fl s | Fl t | Fl Fl test
|
||||
.Op Fl T | Fl Fl tokens
|
||||
.Op Fl 5 | Fl Fl v5
|
||||
@@ -67,17 +65,6 @@ credential cache to list
|
||||
.It Fl s , Fl t , Fl Fl test
|
||||
Test for there being an active and valid TGT for the local realm of
|
||||
the user in the credential cache.
|
||||
.It Fl Fl extract-kx509-cert= Ns Ar hx509-store
|
||||
An hx509 store specification, such as
|
||||
.Va DER-FILE:/path/to/der/file ,
|
||||
.Va PEM-FILE:/path/to/PEM/file ,
|
||||
.Va FILE:/path/to/PEM/file ,
|
||||
or
|
||||
.Va PKCS12:/path/to/PKCS#12/file
|
||||
into which to store any PKIX certificate and private key
|
||||
(unencrypted) that may have been acquired with the kx509 protocol
|
||||
and stored in the
|
||||
.Ns Ar ccache.
|
||||
.It Fl T , Fl Fl tokens
|
||||
display AFS tokens
|
||||
.It Fl 5 , Fl Fl v5
|
||||
|
102
kuser/klist.c
102
kuser/klist.c
@@ -36,10 +36,7 @@
|
||||
#include "kuser_locl.h"
|
||||
#include "parse_units.h"
|
||||
#include "heimtools-commands.h"
|
||||
#include <kx509_asn1.h>
|
||||
#undef HC_DEPRECATED_CRYPTO
|
||||
#include "../lib/hx509/hx_locl.h"
|
||||
#include "hx509-private.h"
|
||||
|
||||
static char*
|
||||
printable_time_internal(time_t t, int x)
|
||||
@@ -264,28 +261,15 @@ print_tickets(krb5_context context,
|
||||
int do_verbose,
|
||||
int do_flags,
|
||||
int do_hidden,
|
||||
int do_json,
|
||||
const char *hx509_store)
|
||||
int do_json)
|
||||
{
|
||||
char *str, *name, *fullname;
|
||||
char *kx509_realm = NULL;
|
||||
hx509_private_key key = NULL;
|
||||
hx509_context hx509ctx = NULL;
|
||||
hx509_certs certs = NULL;
|
||||
hx509_cert cert = NULL;
|
||||
krb5_error_code kx509_ret = 0;
|
||||
krb5_error_code ret;
|
||||
krb5_cc_cursor cursor;
|
||||
krb5_creds creds;
|
||||
krb5_deltat sec;
|
||||
rtbl_t ct = NULL;
|
||||
int print_comma = 0;
|
||||
int kx509_disabled = 0;
|
||||
int cert_stored = 0;
|
||||
int cert_seen = 0;
|
||||
|
||||
if (hx509_store)
|
||||
kx509_ret = hx509_context_init(&hx509ctx);
|
||||
|
||||
ret = krb5_unparse_name (context, principal, &str);
|
||||
if (ret)
|
||||
@@ -358,45 +342,6 @@ print_tickets(krb5_context context,
|
||||
if (do_verbose && do_json)
|
||||
printf("\"tickets\" : [");
|
||||
while ((ret = krb5_cc_next_cred(context, ccache, &cursor, &creds)) == 0) {
|
||||
if (krb5_is_config_principal(context, creds.server) &&
|
||||
krb5_principal_get_num_comp(context, creds.server) == 2 &&
|
||||
hx509_store) {
|
||||
const char *s;
|
||||
|
||||
s = krb5_principal_get_comp_string(context, creds.server, 1);
|
||||
if (strcmp(s, "kx509_service_status") == 0) {
|
||||
kx509_disabled = 1;
|
||||
} else if (strcmp(s, "kx509_service_realm") == 0) {
|
||||
kx509_realm = strndup(creds.ticket.data, creds.ticket.length);
|
||||
} else if (strcmp(s, "kx509cert") == 0) {
|
||||
cert = hx509_cert_init_data(hx509ctx, creds.ticket.data,
|
||||
creds.ticket.length, NULL);
|
||||
} else if (strcmp(s, "kx509key") == 0) {
|
||||
(void) hx509_parse_private_key(hx509ctx, NULL,
|
||||
creds.ticket.data,
|
||||
creds.ticket.length,
|
||||
HX509_KEY_FORMAT_PKCS8, &key);
|
||||
}
|
||||
if (hx509ctx && cert && key && !cert_seen) {
|
||||
/* Now store the cert and key into the given hx509 store */
|
||||
(void) _hx509_cert_assign_key(cert, key);
|
||||
kx509_ret = hx509_certs_init(hx509ctx, hx509_store,
|
||||
HX509_CERTS_CREATE, NULL, &certs);
|
||||
if (kx509_ret == 0)
|
||||
kx509_ret = hx509_certs_add(hx509ctx, certs, cert);
|
||||
if (kx509_ret == 0)
|
||||
kx509_ret = hx509_certs_store(hx509ctx, certs, 0, NULL);
|
||||
|
||||
/*
|
||||
* Wait till we're done listing the ccache to complain about
|
||||
* failing to extract the cert and priv key.
|
||||
*/
|
||||
cert_seen = 1;
|
||||
if (kx509_ret == 0)
|
||||
cert_stored = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!do_hidden && krb5_is_config_principal(context, creds.server)) {
|
||||
;
|
||||
} else if (do_verbose) {
|
||||
@@ -415,40 +360,6 @@ print_tickets(krb5_context context,
|
||||
if (ret)
|
||||
krb5_err(context, 1, ret, "krb5_cc_end_seq_get");
|
||||
|
||||
/* Finish kx509 extraction error checking */
|
||||
if (hx509_store && cert_seen && !cert_stored) {
|
||||
if (!hx509ctx)
|
||||
krb5_err(context, 1, kx509_ret,
|
||||
N_("Failed to store certificate and private key "
|
||||
"in %s due to failure to initialize context: %s", ""),
|
||||
hx509_store, hx509_get_error_string(hx509ctx, kx509_ret));
|
||||
if (!cert || !key)
|
||||
krb5_err(context, 1, kx509_ret,
|
||||
N_("Failed to store certificate and private key "
|
||||
"in %s due to failure to parse them: %s", ""),
|
||||
hx509_store, hx509_get_error_string(hx509ctx, kx509_ret));
|
||||
krb5_err(context, 1, kx509_ret, N_("Failed to store certificate and "
|
||||
"private key in %s", ""),
|
||||
hx509_store);
|
||||
}
|
||||
if (hx509_store && !cert_seen) {
|
||||
/* No PKIX creds in ccache, but maybe we can run kx509 now */
|
||||
if (kx509_disabled)
|
||||
krb5_errx(context, 1, N_("The kx509 protocol is disabled at the "
|
||||
"KDC for realm %s", ""),
|
||||
kx509_realm ? kx509_realm : "<out of memory>");
|
||||
ret = krb5_kx509_ext(context, ccache, NULL, NULL, NULL, 0, hx509_store,
|
||||
NULL);
|
||||
if (ret)
|
||||
krb5_err(context, 1, ret, N_("Failed to acquire certificate and "
|
||||
"store it and private key in %s", ""),
|
||||
hx509_store);
|
||||
}
|
||||
hx509_private_key_free(&key);
|
||||
hx509_certs_free(&certs);
|
||||
hx509_cert_free(cert);
|
||||
hx509_context_free(&hx509ctx);
|
||||
|
||||
print_comma = 0;
|
||||
if(!do_verbose) {
|
||||
rtbl_format(ct, stdout);
|
||||
@@ -566,7 +477,7 @@ static int
|
||||
display_v5_ccache (krb5_context context, krb5_ccache ccache,
|
||||
int do_test, int do_verbose,
|
||||
int do_flags, int do_hidden,
|
||||
int do_json, const char *hx509_store)
|
||||
int do_json)
|
||||
{
|
||||
krb5_error_code ret;
|
||||
krb5_principal principal;
|
||||
@@ -591,7 +502,7 @@ display_v5_ccache (krb5_context context, krb5_ccache ccache,
|
||||
exit_status = check_expiration(context, ccache, NULL);
|
||||
else
|
||||
print_tickets (context, ccache, principal, do_verbose,
|
||||
do_flags, do_hidden, do_json, hx509_store);
|
||||
do_flags, do_hidden, do_json);
|
||||
|
||||
ret = krb5_cc_close (context, ccache);
|
||||
if (ret)
|
||||
@@ -738,8 +649,8 @@ klist(struct klist_options *opt, int argc, char **argv)
|
||||
|
||||
exit_status |= display_v5_ccache(heimtools_context, id, do_test,
|
||||
do_verbose, opt->flags_flag,
|
||||
opt->hidden_flag, opt->json_flag,
|
||||
opt->extract_kx509_cert_string);
|
||||
opt->hidden_flag,
|
||||
opt->json_flag);
|
||||
if (!opt->json_flag)
|
||||
printf("\n\n");
|
||||
|
||||
@@ -760,8 +671,7 @@ klist(struct klist_options *opt, int argc, char **argv)
|
||||
}
|
||||
exit_status = display_v5_ccache(heimtools_context, id, do_test,
|
||||
do_verbose, opt->flags_flag,
|
||||
opt->hidden_flag, opt->json_flag,
|
||||
opt->extract_kx509_cert_string);
|
||||
opt->hidden_flag, opt->json_flag);
|
||||
}
|
||||
}
|
||||
|
||||
|
128
kuser/kx509.1
Normal file
128
kuser/kx509.1
Normal file
@@ -0,0 +1,128 @@
|
||||
.\" Copyright (c) 2019 Kungliga Tekniska Högskolan
|
||||
.\" (Royal Institute of Technology, Stockholm, Sweden).
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\"
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\"
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\"
|
||||
.\" 3. Neither the name of the Institute nor the names of its contributors
|
||||
.\" may be used to endorse or promote products derived from this software
|
||||
.\" without specific prior written permission.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" $Id$
|
||||
.\"
|
||||
.Dd October 6, 2005
|
||||
.Dt KLIST 1
|
||||
.Os HEIMDAL
|
||||
.Sh NAME
|
||||
.Nm kx509
|
||||
.Nd acquire or extract certificates using Kerberos credentials
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Bk -words
|
||||
.Oo Fl c Ar cache \*(Ba Xo
|
||||
.Fl Fl cache= Ns Ar cache
|
||||
.Xc
|
||||
.Oc
|
||||
.Oo Fl s \*(Ba Xo
|
||||
.Fl Fl save
|
||||
.Xc
|
||||
.Oc
|
||||
.Oo Fl o Ar store \*(Ba Xo
|
||||
.Fl Fl out= Ns Ar store
|
||||
.Xc
|
||||
.Oc
|
||||
.Oo Fl x \*(Ba Xo
|
||||
.Fl Fl extract
|
||||
.Xc
|
||||
.Oc
|
||||
.Oo Fl t \*(Ba Xo
|
||||
.Fl Fl test
|
||||
.Xc
|
||||
.Oc
|
||||
.Oo Fl C Ar PKCS10:filename \*(Ba Xo
|
||||
.Fl Fl csr= Ns Ar PKCS10:filename
|
||||
.Xc
|
||||
.Oc
|
||||
.Oo Fl C Ar PKCS10:filename \*(Ba Xo
|
||||
.Fl Fl csr= Ns Ar PKCS10:filename
|
||||
.Xc
|
||||
.Oc
|
||||
.Oo Fl K Ar hx509-store \*(Ba Xo
|
||||
.Fl Fl private-key= Ns Ar hx509-store
|
||||
.Xc
|
||||
.Oc
|
||||
.Oo Fl r Ar realm \*(Ba Xo
|
||||
.Fl Fl realm= Ns Ar realm
|
||||
.Xc
|
||||
.Oc
|
||||
.Op Fl Fl help
|
||||
.Ek
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
acquires PKIX credentials from a credential cache using the kx509
|
||||
protocol, or extracts PKIX credentials stored in a credential
|
||||
cache.
|
||||
.Pp
|
||||
Options supported:
|
||||
.Bl -tag -width Ds
|
||||
.It Fl c Ar cache , Fl Fl cache= Ns Ar cache
|
||||
credential cache to use (if not given, then the default will be
|
||||
used).
|
||||
.It Fl t , Fl Fl test
|
||||
Test for there being an active and valid certificate in the
|
||||
credential cache.
|
||||
.It Fl x , Fl Fl extract
|
||||
Extract, rather than acquire credentials.
|
||||
.It Fl s , Fl Fl save
|
||||
save the acquired certificate and the private key used in the
|
||||
given credential cache.
|
||||
.It Fl o , Fl Fl out= Ns Ar hx509-store
|
||||
An hx509 store specification, such as
|
||||
.Va DER-FILE:/path/to/der/file ,
|
||||
.Va PEM-FILE:/path/to/PEM/file ,
|
||||
.Va FILE:/path/to/PEM/file ,
|
||||
or
|
||||
.Va PKCS12:/path/to/PKCS#12/file
|
||||
into which to store any PKIX certificate and private key
|
||||
(unencrypted) that may have been acquired with the kx509 protocol
|
||||
and stored in the
|
||||
.Ns Ar ccache.
|
||||
.It Fl r Ar realm, Fl Fl realm= Ns Ar realm
|
||||
specify the name of the realm whose kx509 service to use.
|
||||
.It Fl K Ar store, Fl Fl private-key= Ns Ar store
|
||||
use the private key from the given hx509 store for requesting a
|
||||
certificate.
|
||||
.It Fl C Ar csr, Fl Fl csr= Ns Ar certificate-request
|
||||
specify a CSR to use, which must be a string of the form
|
||||
PKCS10:filename and which must contain the DER encoding of a
|
||||
PKCS#10 certification request.
|
||||
.El
|
||||
.Pp
|
||||
The
|
||||
.Nm hxtool(1)
|
||||
command can be used to create private keys and CSRs.
|
||||
.Sh SEE ALSO
|
||||
.Xr kdestroy 1 ,
|
||||
.Xr kinit 1 ,
|
||||
.Xr hxtool 1
|
256
kuser/kx509.c
Normal file
256
kuser/kx509.c
Normal file
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Kungliga Tekniska Högskolan
|
||||
* (Royal Institute of Technology, Stockholm, Sweden).
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "kuser_locl.h"
|
||||
#include "heimtools-commands.h"
|
||||
#include <kx509_asn1.h>
|
||||
#undef HC_DEPRECATED_CRYPTO
|
||||
#include "../lib/hx509/hx_locl.h"
|
||||
#include "../lib/krb5/krb5_locl.h"
|
||||
#include "hx509-private.h"
|
||||
|
||||
static void
|
||||
validate(krb5_context context,
|
||||
const char *hx509_store,
|
||||
krb5_data *der_cert,
|
||||
krb5_data *pkcs8_priv_key)
|
||||
{
|
||||
hx509_context hx509ctx = NULL;
|
||||
hx509_private_key key = NULL;
|
||||
hx509_cert cert;
|
||||
krb5_error_code ret;
|
||||
|
||||
ret = hx509_context_init(&hx509ctx);
|
||||
if (ret)
|
||||
krb5_err(context, 1, ret, "hx509 context init");
|
||||
|
||||
cert = hx509_cert_init_data(hx509ctx, der_cert->data,
|
||||
der_cert->length, NULL);
|
||||
if (cert == NULL)
|
||||
krb5_err(context, 1, errno, "certificate could not be loaded");
|
||||
ret = hx509_parse_private_key(hx509ctx, NULL, pkcs8_priv_key->data,
|
||||
pkcs8_priv_key->length,
|
||||
HX509_KEY_FORMAT_PKCS8, &key);
|
||||
if (ret)
|
||||
krb5_err(context, 1, ret, "certificate could not be loaded");
|
||||
if (hx509_cert_get_notAfter(cert) < time(NULL))
|
||||
krb5_errx(context, 1, "certificate is expired");
|
||||
hx509_private_key_free(&key);
|
||||
hx509_cert_free(cert);
|
||||
hx509_context_free(&hx509ctx);
|
||||
}
|
||||
|
||||
static krb5_error_code
|
||||
add1_2chain(hx509_context hx509ctx, void *d, hx509_cert cert)
|
||||
{
|
||||
heim_octet_string os;
|
||||
krb5_error_code ret;
|
||||
Certificates *cs = d;
|
||||
Certificate c;
|
||||
size_t len;
|
||||
|
||||
|
||||
ret = hx509_cert_binary(hx509ctx, cert, &os);
|
||||
if (ret == 0)
|
||||
ASN1_MALLOC_ENCODE(Certificate, os.data, os.length, &c, &len, ret);
|
||||
der_free_octet_string(&os);
|
||||
if (ret == 0) {
|
||||
add_Certificates(cs, &c);
|
||||
free_Certificate(&c);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static krb5_error_code
|
||||
add_chain(hx509_context hx509ctx, hx509_certs certs, krb5_data *chain)
|
||||
{
|
||||
krb5_error_code ret;
|
||||
Certificates cs;
|
||||
size_t len;
|
||||
|
||||
ret = decode_Certificates(chain->data, chain->length, &cs, &len);
|
||||
if (ret == 0) {
|
||||
ret = hx509_certs_iter_f(hx509ctx, certs, add1_2chain, &cs);
|
||||
free_Certificates(&cs);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
store(krb5_context context,
|
||||
const char *hx509_store,
|
||||
krb5_data *der_cert,
|
||||
krb5_data *pkcs8_priv_key,
|
||||
krb5_data *chain)
|
||||
{
|
||||
hx509_context hx509ctx = NULL;
|
||||
hx509_private_key key = NULL;
|
||||
hx509_certs certs;
|
||||
hx509_cert cert;
|
||||
char *store_exp = NULL;
|
||||
krb5_error_code ret;
|
||||
|
||||
if (hx509_store == NULL) {
|
||||
hx509_store = krb5_config_get_string(context, NULL, "libdefaults",
|
||||
"kx509_store", NULL);
|
||||
if (hx509_store) {
|
||||
ret = _krb5_expand_path_tokens(context, hx509_store, 1, &store_exp);
|
||||
if (ret)
|
||||
krb5_err(context, 1, ret, "expanding tokens in default "
|
||||
"hx509 store");
|
||||
hx509_store = store_exp;
|
||||
}
|
||||
}
|
||||
if (hx509_store == NULL)
|
||||
krb5_errx(context, 1, "no hx509 store given and no default hx509 "
|
||||
"store configured");
|
||||
|
||||
ret = hx509_context_init(&hx509ctx);
|
||||
if (ret)
|
||||
krb5_err(context, 1, ret, "hx509 context init");
|
||||
|
||||
cert = hx509_cert_init_data(hx509ctx, der_cert->data,
|
||||
der_cert->length, NULL);
|
||||
if (cert == NULL)
|
||||
krb5_err(context, 1, errno, "certificate could not be loaded");
|
||||
ret = hx509_parse_private_key(hx509ctx, NULL, pkcs8_priv_key->data,
|
||||
pkcs8_priv_key->length,
|
||||
HX509_KEY_FORMAT_PKCS8, &key);
|
||||
if (ret)
|
||||
krb5_err(context, 1, ret, "certificate could not be loaded");
|
||||
(void) _hx509_cert_assign_key(cert, key);
|
||||
|
||||
ret = hx509_certs_init(hx509ctx, hx509_store, HX509_CERTS_CREATE, NULL,
|
||||
&certs);
|
||||
if (ret == 0)
|
||||
ret = hx509_certs_add(hx509ctx, certs, cert);
|
||||
if (ret == 0)
|
||||
add_chain(hx509ctx, certs, chain);
|
||||
if (ret == 0)
|
||||
ret = hx509_certs_store(hx509ctx, certs, 0, NULL);
|
||||
if (ret)
|
||||
krb5_err(context, 1, ret, "certificate could not be stored");
|
||||
|
||||
hx509_private_key_free(&key);
|
||||
hx509_certs_free(&certs);
|
||||
hx509_cert_free(cert);
|
||||
hx509_context_free(&hx509ctx);
|
||||
free(store_exp);
|
||||
}
|
||||
|
||||
static void
|
||||
set_csr(krb5_context context, krb5_kx509_req_ctx req, const char *csr_file)
|
||||
{
|
||||
krb5_error_code ret;
|
||||
krb5_data d;
|
||||
|
||||
if (strncmp(csr_file, "PKCS10:", sizeof("PKCS10:") - 1) != 0)
|
||||
krb5_errx(context, 1, "CSR filename must start with \"PKCS10:\"");
|
||||
ret = rk_undumpdata(csr_file + sizeof("PKCS10:") - 1, &d.data, &d.length);
|
||||
if (ret)
|
||||
krb5_err(context, 1, ret, "could not read CSR");
|
||||
ret = krb5_kx509_ctx_set_csr_der(context, req, &d);
|
||||
if (ret)
|
||||
krb5_err(context, 1, ret, "hx509 context init");
|
||||
}
|
||||
|
||||
int
|
||||
kx509(struct kx509_options *opt, int argc, char **argv)
|
||||
{
|
||||
krb5_kx509_req_ctx req = NULL;
|
||||
krb5_context context = heimtools_context;
|
||||
krb5_error_code ret;
|
||||
krb5_ccache ccout = NULL;
|
||||
krb5_ccache cc = NULL;
|
||||
|
||||
if (opt->cache_string)
|
||||
ret = krb5_cc_resolve(context, opt->cache_string, &cc);
|
||||
else if (opt->save_flag || opt->extract_flag)
|
||||
ret = krb5_cc_default(context, &cc);
|
||||
if (ret)
|
||||
krb5_err(context, 1, ret, "no input credential cache");
|
||||
if (opt->save_flag)
|
||||
ccout = cc;
|
||||
|
||||
if (opt->test_flag &&
|
||||
(opt->extract_flag || opt->csr_string || opt->private_key_string))
|
||||
krb5_errx(context, 1, "--test is exclusive of --extract, --csr, and "
|
||||
"--private-key");
|
||||
|
||||
if (opt->extract_flag && (opt->csr_string || opt->private_key_string))
|
||||
krb5_errx(context, 1, "--extract is exclusive of --csr and --private-key");
|
||||
|
||||
if (opt->test_flag || opt->extract_flag) {
|
||||
krb5_data der_cert, pkcs8_key, chain;
|
||||
|
||||
der_cert.data = pkcs8_key.data = chain.data = NULL;
|
||||
der_cert.length = pkcs8_key.length = chain.length = 0;
|
||||
ret = krb5_cc_get_config(context, cc, NULL, "kx509cert", &der_cert);
|
||||
if (ret == 0)
|
||||
ret = krb5_cc_get_config(context, cc, NULL, "kx509key", &pkcs8_key);
|
||||
if (ret == 0)
|
||||
ret = krb5_cc_get_config(context, cc, NULL, "kx509cert-chain", &chain);
|
||||
if (ret)
|
||||
krb5_err(context, 1, ret, "no certificate in credential cache");
|
||||
if (opt->test_flag)
|
||||
validate(context, opt->out_string, &der_cert, &pkcs8_key);
|
||||
else
|
||||
store(context, opt->out_string, &der_cert, &pkcs8_key, &chain);
|
||||
krb5_data_free(&pkcs8_key);
|
||||
krb5_data_free(&der_cert);
|
||||
krb5_data_free(&chain);
|
||||
} else {
|
||||
/*
|
||||
* XXX We should delete any cc configs that indicate that kx509 is
|
||||
* disabled.
|
||||
*/
|
||||
ret = krb5_kx509_ctx_init(context, &req);
|
||||
if (ret == 0 && opt->realm_string)
|
||||
ret = krb5_kx509_ctx_set_realm(context, req, opt->realm_string);
|
||||
if (ret == 0 && opt->csr_string)
|
||||
set_csr(context, req, opt->csr_string);
|
||||
if (ret == 0 && opt->private_key_string)
|
||||
ret = krb5_kx509_ctx_set_key(context, req, opt->private_key_string);
|
||||
if (ret)
|
||||
krb5_err(context, 1, ret, "could not setup kx509 request options");
|
||||
|
||||
ret = krb5_kx509_ext(context, req, cc, opt->out_string, ccout);
|
||||
if (ret)
|
||||
krb5_err(context, 1, ret, "could not acquire certificate with kx509");
|
||||
krb5_kx509_ctx_free(context, &req);
|
||||
}
|
||||
|
||||
krb5_cc_close(context, cc);
|
||||
|
||||
return 0;
|
||||
}
|
Reference in New Issue
Block a user