2 * Copyright (c) 2019 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * This plugin authorizes requested certificate SANs and EKUs by checking for
36 * existence of files of the form:
39 * /<path>/<princ>/<ext>-<value>
41 * where <path> is the value of:
43 * [kdc] simple_csr_authorizer_directory = PATH
45 * <princ> is a requesting client principal name with all characters other than
46 * alphanumeric, '-', '_', and non-leading '.' URL-encoded.
57 * and <value> is a display form of the SAN or EKU OID, with SANs URL-encoded
58 * just like principal names (see above).
60 * OIDs are of the form "1.2.3.4.5".
62 * Only digitalSignature and nonRepudiation key usage values are permitted.
66 #include <sys/types.h>
79 #include <common_plugin.h>
80 #include <csr_authorizer_plugin.h>
83 * string_encode_sz() and string_encode() encode a string to be safe for use as
84 * a file name. They function very much like URL encoders, but '~' also gets
85 * encoded, and '@', '-', '_', and non-leading '.' do not.
87 * A corresponding decoder is not needed.
90 string_encode_sz(const char *in
)
92 size_t sz
= strlen(in
);
117 string_encode(const char *in
)
119 size_t len
= strlen(in
);
120 size_t sz
= string_encode_sz(in
);
125 if ((s
= malloc(sz
+ 1)) == NULL
)
129 for (i
= k
= 0; i
< len
; i
++, first
= 0) {
130 unsigned char c
= ((const unsigned char *)in
)[i
];
141 s
[k
++] = "0123456789abcdef"[(c
&0xff)>>4];
142 s
[k
++] = "0123456789abcdef"[(c
&0x0f)];
152 s
[k
++] = "0123456789abcdef"[(c
&0xff)>>4];
153 s
[k
++] = "0123456789abcdef"[(c
&0x0f)];
167 static KRB5_LIB_CALL krb5_error_code
169 krb5_context context
,
172 krb5_const_principal client
,
173 krb5_boolean
*result
)
176 hx509_context hx509ctx
= NULL
;
183 if ((d
= krb5_config_get_string(context
, NULL
, app
? app
: "kdc",
184 "simple_csr_authorizer_directory",
186 return KRB5_PLUGIN_NO_HANDLE
;
188 if ((ret
= hx509_context_init(&hx509ctx
)))
191 if ((ret
= krb5_unparse_name(context
, client
, &princ
)))
194 s
= string_encode(princ
);
203 for (i
= 0; ret
== 0; i
++) {
204 hx509_san_type san_type
;
210 ret
= hx509_request_get_san(csr
, i
, &san_type
, &s
);
214 case HX509_SAN_TYPE_EMAIL
:
217 case HX509_SAN_TYPE_DNSNAME
:
220 case HX509_SAN_TYPE_XMPP
:
223 case HX509_SAN_TYPE_PKINIT
:
226 case HX509_SAN_TYPE_MS_UPN
:
236 if ((san
= string_encode(s
)) == NULL
||
237 asprintf(&p
, "%s/%s/%s-%s", d
, princ
, prefix
, san
) == -1 ||
242 ret
= stat(p
, &st
) == -1 ? errno
: 0;
248 ret
= hx509_request_authorize_san(csr
, i
);
251 if (ret
== HX509_NO_ITEM
)
256 for (i
= 0; ret
== 0; i
++) {
260 ret
= hx509_request_get_eku(csr
, i
, &s
);
263 if (asprintf(&p
, "%s/%s/eku-%s", d
, princ
, s
) == -1 || p
== NULL
)
265 ret
= stat(p
, &st
) == -1 ? errno
: 0;
270 ret
= hx509_request_authorize_eku(csr
, i
);
272 if (ret
== HX509_NO_ITEM
)
277 ku
= int2KeyUsage(0);
278 ku
.digitalSignature
= 1;
279 ku
.nonRepudiation
= 1;
280 hx509_request_authorize_ku(csr
, ku
);
287 /* Allow another plugin to get a crack at this */
288 ret
= KRB5_PLUGIN_NO_HANDLE
;
292 ret
= krb5_enomem(context
);
296 hx509_context_free(&hx509ctx
);
302 static KRB5_LIB_CALL krb5_error_code
303 simple_csr_authorizer_init(krb5_context context
, void **c
)
309 static KRB5_LIB_CALL
void
310 simple_csr_authorizer_fini(void *c
)
314 static krb5plugin_csr_authorizer_ftable plug_desc
=
315 { 1, simple_csr_authorizer_init
, simple_csr_authorizer_fini
, authorize
};
317 static krb5plugin_csr_authorizer_ftable
*plugs
[] = { &plug_desc
};
320 simple_csr_authorizer_get_instance(const char *libname
)
322 if (strcmp(libname
, "krb5") == 0)
323 return krb5_get_instance(libname
);
324 if (strcmp(libname
, "kdc") == 0)
325 return kdc_get_instance(libname
);
326 if (strcmp(libname
, "hx509") == 0)
327 return hx509_get_instance(libname
);
331 krb5_plugin_load_ft kdc_csr_authorizer_plugin_load
;
333 krb5_error_code KRB5_CALLCONV
334 kdc_csr_authorizer_plugin_load(heim_pcontext context
,
335 krb5_get_instance_func_t
*get_instance
,
337 krb5_plugin_common_ftable_cp
**plugins
)
339 *get_instance
= simple_csr_authorizer_get_instance
;
340 *num_plugins
= sizeof(plugs
) / sizeof(plugs
[0]);
341 *plugins
= (krb5_plugin_common_ftable_cp
*)plugs
;