xref: /netbsd-src/external/bsd/openldap/dist/servers/slapd/overlays/autoca.c (revision 549b59ed3ccf0d36d3097190a0db27b770f3a839)
1 /*	$NetBSD: autoca.c,v 1.2 2021/08/14 16:15:02 christos Exp $	*/
2 
3 /* autoca.c - Automatic Certificate Authority */
4 /* $OpenLDAP$ */
5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6  *
7  * Copyright 2009-2021 The OpenLDAP Foundation.
8  * Copyright 2009-2018 by Howard Chu.
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted only as authorized by the OpenLDAP
13  * Public License.
14  *
15  * A copy of this license is available in the file LICENSE in the
16  * top-level directory of the distribution or, alternatively, at
17  * <http://www.OpenLDAP.org/license.html>.
18  */
19 /* ACKNOWLEDGEMENTS:
20  * This work was initially developed by Howard Chu for inclusion in
21  * OpenLDAP Software.
22  */
23 
24 #include <sys/cdefs.h>
25 __RCSID("$NetBSD: autoca.c,v 1.2 2021/08/14 16:15:02 christos Exp $");
26 
27 #include "portable.h"
28 
29 #ifdef SLAPD_OVER_AUTOCA
30 
31 #include <stdio.h>
32 
33 #include <ac/string.h>
34 #include <ac/socket.h>
35 
36 #include "lutil.h"
37 #include "slap.h"
38 #include "slap-config.h"
39 
40 #include <openssl/x509.h>
41 #include <openssl/x509v3.h>
42 #include <openssl/evp.h>
43 #include <openssl/bn.h>
44 
45 /* Starting with OpenSSL 1.1.0, rsa.h is no longer included in
46  * x509.h, so we need to explicitly include it for the
47  * call to EVP_PKEY_CTX_set_rsa_keygen_bits
48  */
49 
50 #if OPENSSL_VERSION_NUMBER >= 0x10100000
51 #include <openssl/rsa.h>
52 #define X509_get_notBefore(x)	X509_getm_notBefore(x)
53 #define X509_get_notAfter(x)	X509_getm_notAfter(x)
54 #endif
55 
56 /* This overlay implements a certificate authority that can generate
57  * certificates automatically for any entry in the directory.
58  * On startup it generates a self-signed CA cert for the directory's
59  * suffix entry and uses this to sign all other certs that it generates.
60  * User and server certs are generated on demand, using a Search request.
61  */
62 
63 #define LBER_TAG_OID        ((ber_tag_t) 0x06UL)
64 #define LBER_TAG_UTF8       ((ber_tag_t) 0x0cUL)
65 
66 #define KEYBITS	2048
67 #define MIN_KEYBITS	512
68 
69 #define ACA_SCHEMA_ROOT	"1.3.6.1.4.1.4203.666.11.11"
70 
71 #define ACA_SCHEMA_AT ACA_SCHEMA_ROOT ".1"
72 #define ACA_SCHEMA_OC ACA_SCHEMA_ROOT ".2"
73 
74 static AttributeDescription *ad_caCert, *ad_caPkey, *ad_usrCert, *ad_usrPkey;
75 static AttributeDescription *ad_mail, *ad_ipaddr;
76 static ObjectClass *oc_caObj, *oc_usrObj;
77 
78 static char *aca_attrs[] = {
79 	"( " ACA_SCHEMA_AT ".1 NAME 'cAPrivateKey' "
80 		"DESC 'X.509 CA private key, use ;binary' "
81 		"SUP pKCS8PrivateKey )",
82 	"( " ACA_SCHEMA_AT ".2 NAME 'userPrivateKey' "
83 		"DESC 'X.509 user private key, use ;binary' "
84 		"SUP pKCS8PrivateKey )",
85 	NULL
86 };
87 
88 static struct {
89 	char *at;
90 	AttributeDescription **ad;
91 } aca_attr2[] = {
92 	{ "cACertificate;binary", &ad_caCert },
93 	{ "cAPrivateKey;binary", &ad_caPkey },
94 	{ "userCertificate;binary", &ad_usrCert },
95 	{ "userPrivateKey;binary", &ad_usrPkey },
96 	{ "mail", &ad_mail },
97 	{ NULL }
98 };
99 
100 static struct {
101 	char *ot;
102 	ObjectClass **oc;
103 } aca_ocs[] = {
104 	{ "( " ACA_SCHEMA_OC ".1 NAME 'autoCA' "
105 		"DESC 'Automated PKI certificate authority' "
106 		"SUP pkiCA AUXILIARY "
107 		"MAY cAPrivateKey )", &oc_caObj },
108 	{ "( " ACA_SCHEMA_OC ".2 NAME 'autoCAuser' "
109 		"DESC 'Automated PKI CA user' "
110 		"SUP pkiUser AUXILIARY "
111 		"MAY userPrivateKey )", &oc_usrObj },
112 	{ NULL }
113 };
114 
115 typedef struct autoca_info {
116 	X509 *ai_cert;
117 	EVP_PKEY *ai_pkey;
118 	ObjectClass *ai_usrclass;
119 	ObjectClass *ai_srvclass;
120 	struct berval ai_localdn;
121 	struct berval ai_localndn;
122 	int ai_usrkeybits;
123 	int ai_srvkeybits;
124 	int ai_cakeybits;
125 	int ai_usrdays;
126 	int ai_srvdays;
127 	int ai_cadays;
128 } autoca_info;
129 
130 /* Rewrite an LDAP DN in DER form
131  * Input must be valid DN, therefore no error checking is done here.
132  */
autoca_dnbv2der(Operation * op,struct berval * bv,struct berval * der)133 static int autoca_dnbv2der( Operation *op, struct berval *bv, struct berval *der )
134 {
135 	BerElementBuffer berbuf;
136 	BerElement *ber = (BerElement *)&berbuf;
137 	LDAPDN dn;
138 	LDAPRDN rdn;
139 	LDAPAVA *ava;
140 	AttributeDescription *ad;
141 	int irdn, iava;
142 
143 	ldap_bv2dn_x( bv, &dn, LDAP_DN_FORMAT_LDAP, op->o_tmpmemctx );
144 
145 	ber_init2( ber, NULL, LBER_USE_DER );
146 	ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
147 
148 	/* count RDNs, we need them in reverse order */
149 	for (irdn = 0; dn[irdn]; irdn++);
150 	irdn--;
151 
152 	/* DN is a SEQuence of RDNs */
153 	ber_start_seq( ber, LBER_SEQUENCE );
154 	for (; irdn >=0; irdn--)
155 	{
156 		/* RDN is a SET of AVAs */
157 		ber_start_set( ber, LBER_SET );
158 		rdn = dn[irdn];
159 		for (iava = 0; rdn[iava]; iava++)
160 		{
161 			const char *text;
162 			char oid[1024];
163 			struct berval bvo = { sizeof(oid), oid };
164 			struct berval bva;
165 
166 			/* AVA is a SEQuence of attr and value */
167 			ber_start_seq( ber, LBER_SEQUENCE );
168 			ava = rdn[iava];
169 			ad = NULL;
170 			slap_bv2ad( &ava->la_attr, &ad, &text );
171 			ber_str2bv( ad->ad_type->sat_oid, 0, 0, &bva );
172 			ber_encode_oid( &bva, &bvo );
173 			ber_put_berval( ber, &bvo, LBER_TAG_OID );
174 			ber_put_berval( ber, &ava->la_value, LBER_TAG_UTF8 );
175 			ber_put_seq( ber );
176 		}
177 		ber_put_set( ber );
178 	}
179 	ber_put_seq( ber );
180 	ber_flatten2( ber, der, 0 );
181 	ldap_dnfree_x( dn, op->o_tmpmemctx );
182 	return 0;
183 }
184 
autoca_genpkey(int bits,EVP_PKEY ** pkey)185 static int autoca_genpkey(int bits, EVP_PKEY **pkey)
186 {
187 	EVP_PKEY_CTX *kctx;
188 	int rc;
189 
190 	kctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
191 	if (kctx == NULL)
192 		return -1;
193 	if (EVP_PKEY_keygen_init(kctx) <= 0)
194 	{
195 		EVP_PKEY_CTX_free(kctx);
196 		return -1;
197 	}
198 	if (EVP_PKEY_CTX_set_rsa_keygen_bits(kctx, bits) <= 0)
199 	{
200 		EVP_PKEY_CTX_free(kctx);
201 		return -1;
202 	}
203 	rc = EVP_PKEY_keygen(kctx, pkey);
204 	EVP_PKEY_CTX_free(kctx);
205 	return rc;
206 }
207 
autoca_signcert(X509 * cert,EVP_PKEY * pkey)208 static int autoca_signcert(X509 *cert, EVP_PKEY *pkey)
209 {
210 	EVP_MD_CTX *ctx = EVP_MD_CTX_create();
211 	EVP_PKEY_CTX *pkctx = NULL;
212 	int rc = -1;
213 
214 	if ( ctx == NULL )
215 		return -1;
216 	if (EVP_DigestSignInit(ctx, &pkctx, NULL, NULL, pkey))
217 	{
218 		rc = X509_sign_ctx(cert, ctx);
219 	}
220 	EVP_MD_CTX_destroy(ctx);
221 	return rc;
222 }
223 
224 #define SERIAL_BITS	64	/* should be less than 160 */
225 
226 typedef struct myext {
227 	char *name;
228 	char *value;
229 } myext;
230 
231 static myext CAexts[] = {
232 	{ "subjectKeyIdentifier", "hash" },
233 	{ "authorityKeyIdentifier", "keyid:always,issuer" },
234 	{ "basicConstraints", "critical,CA:true" },
235 	{ "keyUsage", "digitalSignature,cRLSign,keyCertSign" },
236 	{ "nsComment", "OpenLDAP automatic certificate" },
237 	{ NULL }
238 };
239 
240 static myext usrExts[] = {
241 	{ "subjectKeyIdentifier", "hash" },
242 	{ "authorityKeyIdentifier", "keyid:always,issuer" },
243 	{ "basicConstraints", "CA:false" },
244 	{ "keyUsage", "digitalSignature,nonRepudiation,keyEncipherment" },
245 	{ "extendedKeyUsage", "clientAuth,emailProtection,codeSigning" },
246 	{ "nsComment", "OpenLDAP automatic certificate" },
247 	{ NULL }
248 };
249 
250 static myext srvExts[] = {
251 	{ "subjectKeyIdentifier", "hash" },
252 	{ "authorityKeyIdentifier", "keyid:always,issuer" },
253 	{ "basicConstraints", "CA:false" },
254 	{ "keyUsage", "digitalSignature,keyEncipherment" },
255 	{ "extendedKeyUsage", "serverAuth,clientAuth" },
256 	{ "nsComment", "OpenLDAP automatic certificate" },
257 	{ NULL }
258 };
259 
260 typedef struct genargs {
261 	X509 *issuer_cert;
262 	EVP_PKEY *issuer_pkey;
263 	struct berval *subjectDN;
264 	myext *cert_exts;
265 	myext *more_exts;
266 	X509 *newcert;
267 	EVP_PKEY *newpkey;
268 	struct berval dercert;
269 	struct berval derpkey;
270 	int keybits;
271 	int days;
272 } genargs;
273 
autoca_gencert(Operation * op,genargs * args)274 static int autoca_gencert( Operation *op, genargs *args )
275 {
276 	X509_NAME *subj_name, *issuer_name;
277 	X509 *subj_cert;
278 	struct berval derdn;
279 	unsigned char *pp;
280 	EVP_PKEY *evpk = NULL;
281 	int rc;
282 
283 	if ((subj_cert = X509_new()) == NULL)
284 		return -1;
285 
286 	autoca_dnbv2der( op, args->subjectDN, &derdn );
287 	pp = (unsigned char *)derdn.bv_val;
288 	subj_name = d2i_X509_NAME( NULL, (const unsigned char **)&pp, derdn.bv_len );
289 	op->o_tmpfree( derdn.bv_val, op->o_tmpmemctx );
290 	if ( subj_name == NULL )
291 	{
292 fail1:
293 		X509_free( subj_cert );
294 		return -1;
295 	}
296 
297 	rc = autoca_genpkey( args->keybits, &evpk );
298 	if ( rc <= 0 )
299 	{
300 fail2:
301 		if ( subj_name ) X509_NAME_free( subj_name );
302 		goto fail1;
303 	}
304 	/* encode DER in PKCS#8 */
305 	{
306 		PKCS8_PRIV_KEY_INFO *p8inf;
307 		if (( p8inf = EVP_PKEY2PKCS8( evpk )) == NULL )
308 			goto fail2;
309 		args->derpkey.bv_len = i2d_PKCS8_PRIV_KEY_INFO( p8inf, NULL );
310 		args->derpkey.bv_val = op->o_tmpalloc( args->derpkey.bv_len, op->o_tmpmemctx );
311 		pp = (unsigned char *)args->derpkey.bv_val;
312 		i2d_PKCS8_PRIV_KEY_INFO( p8inf, &pp );
313 		PKCS8_PRIV_KEY_INFO_free( p8inf );
314 	}
315 	args->newpkey = evpk;
316 
317 	/* set random serial */
318 	{
319 		BIGNUM *bn = BN_new();
320 		if ( bn == NULL )
321 		{
322 fail3:
323 			EVP_PKEY_free( evpk );
324 			goto fail2;
325 		}
326 		if (!BN_pseudo_rand(bn, SERIAL_BITS, 0, 0))
327 		{
328 			BN_free( bn );
329 			goto fail3;
330 		}
331 		if (!BN_to_ASN1_INTEGER(bn, X509_get_serialNumber(subj_cert)))
332 		{
333 			BN_free( bn );
334 			goto fail3;
335 		}
336 		BN_free(bn);
337 	}
338 	if (args->issuer_cert) {
339 		issuer_name = X509_get_subject_name(args->issuer_cert);
340 	} else {
341 		issuer_name = subj_name;
342 		args->issuer_cert = subj_cert;
343 		args->issuer_pkey = evpk;
344 	}
345 	if (!X509_set_version(subj_cert, 2) ||	/* set version to V3 */
346 		!X509_set_issuer_name(subj_cert, issuer_name) ||
347 		!X509_set_subject_name(subj_cert, subj_name) ||
348 		!X509_gmtime_adj(X509_get_notBefore(subj_cert), 0) ||
349 		!X509_time_adj_ex(X509_get_notAfter(subj_cert), args->days, 0, NULL) ||
350 		!X509_set_pubkey(subj_cert, evpk))
351 	{
352 		goto fail3;
353 	}
354 	X509_NAME_free(subj_name);
355 	subj_name = NULL;
356 
357 	/* set cert extensions */
358 	{
359 		X509V3_CTX ctx;
360 		X509_EXTENSION *ext;
361 		int i;
362 
363 		X509V3_set_ctx(&ctx, args->issuer_cert, subj_cert, NULL, NULL, 0);
364 		for (i=0; args->cert_exts[i].name; i++) {
365 			ext = X509V3_EXT_nconf(NULL, &ctx, args->cert_exts[i].name, args->cert_exts[i].value);
366 			if ( ext == NULL )
367 				goto fail3;
368 			rc = X509_add_ext(subj_cert, ext, -1);
369 			X509_EXTENSION_free(ext);
370 			if ( !rc )
371 				goto fail3;
372 		}
373 		if (args->more_exts) {
374 			for (i=0; args->more_exts[i].name; i++) {
375 				ext = X509V3_EXT_nconf(NULL, &ctx, args->more_exts[i].name, args->more_exts[i].value);
376 				if ( ext == NULL )
377 					goto fail3;
378 				rc = X509_add_ext(subj_cert, ext, -1);
379 				X509_EXTENSION_free(ext);
380 				if ( !rc )
381 					goto fail3;
382 			}
383 		}
384 	}
385 	rc = autoca_signcert( subj_cert, args->issuer_pkey );
386 	if ( rc < 0 )
387 		goto fail3;
388 	args->dercert.bv_len = i2d_X509( subj_cert, NULL );
389 	args->dercert.bv_val = op->o_tmpalloc( args->dercert.bv_len, op->o_tmpmemctx );
390 	pp = (unsigned char *)args->dercert.bv_val;
391 	i2d_X509( subj_cert, &pp );
392 	args->newcert = subj_cert;
393 	return 0;
394 }
395 
396 typedef struct saveargs {
397 	ObjectClass *oc;
398 	struct berval *dercert;
399 	struct berval *derpkey;
400 	slap_overinst *on;
401 	struct berval *dn;
402 	struct berval *ndn;
403 	int isca;
404 } saveargs;
405 
autoca_savecert(Operation * op,saveargs * args)406 static int autoca_savecert( Operation *op, saveargs *args )
407 {
408 	Modifications mod[3], *mp = mod;
409 	struct berval bvs[6], *bp = bvs;
410 	BackendInfo *bi;
411 	slap_callback cb = {0};
412 	SlapReply rs = {REP_RESULT};
413 
414 	if ( args->oc ) {
415 		mp->sml_numvals = 1;
416 		mp->sml_values = bp;
417 		mp->sml_nvalues = NULL;
418 		mp->sml_desc = slap_schema.si_ad_objectClass;
419 		mp->sml_op = LDAP_MOD_ADD;
420 		mp->sml_flags = SLAP_MOD_INTERNAL;
421 		*bp++ = args->oc->soc_cname;
422 		BER_BVZERO( bp );
423 		bp++;
424 		mp->sml_next = mp+1;
425 		mp++;
426 	}
427 	mp->sml_numvals = 1;
428 	mp->sml_values = bp;
429 	mp->sml_nvalues = NULL;
430 	mp->sml_desc = args->isca ? ad_caCert : ad_usrCert;
431 	mp->sml_op = LDAP_MOD_REPLACE;
432 	mp->sml_flags = SLAP_MOD_INTERNAL;
433 	*bp++ = *args->dercert;
434 	BER_BVZERO( bp );
435 	bp++;
436 	mp->sml_next = mp+1;
437 	mp++;
438 
439 	mp->sml_numvals = 1;
440 	mp->sml_values = bp;
441 	mp->sml_nvalues = NULL;
442 	mp->sml_desc = args->isca ? ad_caPkey : ad_usrPkey;
443 	mp->sml_op = LDAP_MOD_ADD;
444 	mp->sml_flags = SLAP_MOD_INTERNAL;
445 	*bp++ = *args->derpkey;
446 	BER_BVZERO( bp );
447 	mp->sml_next = NULL;
448 
449 	cb.sc_response = slap_null_cb;
450 	bi = op->o_bd->bd_info;
451 	op->o_bd->bd_info = args->on->on_info->oi_orig;
452 	op->o_tag = LDAP_REQ_MODIFY;
453 	op->o_callback = &cb;
454 	op->orm_modlist = mod;
455 	op->orm_no_opattrs = 1;
456 	op->o_req_dn = *args->dn;
457 	op->o_req_ndn = *args->ndn;
458 	op->o_bd->be_modify( op, &rs );
459 	op->o_bd->bd_info = bi;
460 	return rs.sr_err;
461 }
462 
463 static const struct berval configDN = BER_BVC("cn=config");
464 
465 /* must run as a pool thread to avoid cn=config deadlock */
466 static void *
autoca_setca_task(void * ctx,void * arg)467 autoca_setca_task( void *ctx, void *arg )
468 {
469 	Connection conn = { 0 };
470 	OperationBuffer opbuf;
471 	Operation *op;
472 	struct berval *cacert = arg;
473 	Modifications mod;
474 	struct berval bvs[2];
475 	slap_callback cb = {0};
476 	SlapReply rs = {REP_RESULT};
477 	const char *text;
478 
479 	connection_fake_init( &conn, &opbuf, ctx );
480 	op = &opbuf.ob_op;
481 
482 	mod.sml_numvals = 1;
483 	mod.sml_values = bvs;
484 	mod.sml_nvalues = NULL;
485 	mod.sml_desc = NULL;
486 	if ( slap_str2ad( "olcTLSCACertificate;binary", &mod.sml_desc, &text ))
487 		goto leave;
488 	mod.sml_op = LDAP_MOD_REPLACE;
489 	mod.sml_flags = SLAP_MOD_INTERNAL;
490 	bvs[0] = *cacert;
491 	BER_BVZERO( &bvs[1] );
492 	mod.sml_next = NULL;
493 
494 	cb.sc_response = slap_null_cb;
495 	op->o_bd = select_backend( (struct berval *)&configDN, 0 );
496 	if ( !op->o_bd )
497 		goto leave;
498 
499 	op->o_tag = LDAP_REQ_MODIFY;
500 	op->o_callback = &cb;
501 	op->orm_modlist = &mod;
502 	op->orm_no_opattrs = 1;
503 	op->o_req_dn = configDN;
504 	op->o_req_ndn = configDN;
505 	op->o_dn = op->o_bd->be_rootdn;
506 	op->o_ndn = op->o_bd->be_rootndn;
507 	op->o_bd->be_modify( op, &rs );
508 leave:
509 	ch_free( arg );
510 	return NULL;
511 }
512 
513 static int
autoca_setca(struct berval * cacert)514 autoca_setca( struct berval *cacert )
515 {
516 	struct berval *bv = ch_malloc( sizeof(struct berval) + cacert->bv_len );
517 	bv->bv_len = cacert->bv_len;
518 	bv->bv_val = (char *)(bv+1);
519 	AC_MEMCPY( bv->bv_val, cacert->bv_val, bv->bv_len );
520 	return ldap_pvt_thread_pool_submit( &connection_pool, autoca_setca_task, bv );
521 }
522 
523 static int
autoca_setlocal(Operation * op,struct berval * cert,struct berval * pkey)524 autoca_setlocal( Operation *op, struct berval *cert, struct berval *pkey )
525 {
526 	Modifications mod[2];
527 	struct berval bvs[4];
528 	slap_callback cb = {0};
529 	SlapReply rs = {REP_RESULT};
530 	const char *text;
531 
532 	mod[0].sml_numvals = 1;
533 	mod[0].sml_values = bvs;
534 	mod[0].sml_nvalues = NULL;
535 	mod[0].sml_desc = NULL;
536 	if ( slap_str2ad( "olcTLSCertificate;binary", &mod[0].sml_desc, &text ))
537 		return -1;
538 	mod[0].sml_op = LDAP_MOD_REPLACE;
539 	mod[0].sml_flags = SLAP_MOD_INTERNAL;
540 	bvs[0] = *cert;
541 	BER_BVZERO( &bvs[1] );
542 	mod[0].sml_next = &mod[1];
543 
544 	mod[1].sml_numvals = 1;
545 	mod[1].sml_values = &bvs[2];
546 	mod[1].sml_nvalues = NULL;
547 	mod[1].sml_desc = NULL;
548 	if ( slap_str2ad( "olcTLSCertificateKey;binary", &mod[1].sml_desc, &text ))
549 		return -1;
550 	mod[1].sml_op = LDAP_MOD_REPLACE;
551 	mod[1].sml_flags = SLAP_MOD_INTERNAL;
552 	bvs[2] = *pkey;
553 	BER_BVZERO( &bvs[3] );
554 	mod[1].sml_next = NULL;
555 
556 	cb.sc_response = slap_null_cb;
557 	op->o_bd = select_backend( (struct berval *)&configDN, 0 );
558 	if ( !op->o_bd )
559 		return -1;
560 
561 	op->o_tag = LDAP_REQ_MODIFY;
562 	op->o_callback = &cb;
563 	op->orm_modlist = mod;
564 	op->orm_no_opattrs = 1;
565 	op->o_req_dn = configDN;
566 	op->o_req_ndn = configDN;
567 	op->o_dn = op->o_bd->be_rootdn;
568 	op->o_ndn = op->o_bd->be_rootndn;
569 	op->o_bd->be_modify( op, &rs );
570 	return rs.sr_err;
571 }
572 
573 enum {
574 	ACA_USRCLASS = 1,
575 	ACA_SRVCLASS,
576 	ACA_USRKEYBITS,
577 	ACA_SRVKEYBITS,
578 	ACA_CAKEYBITS,
579 	ACA_USRDAYS,
580 	ACA_SRVDAYS,
581 	ACA_CADAYS,
582 	ACA_LOCALDN
583 };
584 
autoca_cf(ConfigArgs * c)585 static int autoca_cf( ConfigArgs *c )
586 {
587 	slap_overinst *on = (slap_overinst *)c->bi;
588 	autoca_info *ai = on->on_bi.bi_private;
589 	int rc = 0;
590 
591 	switch( c->op ) {
592 	case SLAP_CONFIG_EMIT:
593 		switch( c->type ) {
594 		case ACA_USRCLASS:
595 			if ( ai->ai_usrclass ) {
596 				c->value_string = ch_strdup( ai->ai_usrclass->soc_cname.bv_val );
597 			} else {
598 				rc = 1;
599 			}
600 			break;
601 		case ACA_SRVCLASS:
602 			if ( ai->ai_srvclass ) {
603 				c->value_string = ch_strdup( ai->ai_srvclass->soc_cname.bv_val );
604 			} else {
605 				rc = 1;
606 			}
607 			break;
608 		case ACA_USRKEYBITS:
609 			c->value_int = ai->ai_usrkeybits;
610 			break;
611 		case ACA_SRVKEYBITS:
612 			c->value_int = ai->ai_srvkeybits;
613 			break;
614 		case ACA_CAKEYBITS:
615 			c->value_int = ai->ai_cakeybits;
616 			break;
617 		case ACA_USRDAYS:
618 			c->value_int = ai->ai_usrdays;
619 			break;
620 		case ACA_SRVDAYS:
621 			c->value_int = ai->ai_srvdays;
622 			break;
623 		case ACA_CADAYS:
624 			c->value_int = ai->ai_cadays;
625 			break;
626 		case ACA_LOCALDN:
627 			if ( !BER_BVISNULL( &ai->ai_localdn )) {
628 				rc = value_add_one( &c->rvalue_vals, &ai->ai_localdn );
629 			} else {
630 				rc = 1;
631 			}
632 			break;
633 		}
634 		break;
635 	case LDAP_MOD_DELETE:
636 		switch( c->type ) {
637 		case ACA_USRCLASS:
638 			ai->ai_usrclass = NULL;
639 			break;
640 		case ACA_SRVCLASS:
641 			ai->ai_srvclass = NULL;
642 			break;
643 		case ACA_LOCALDN:
644 			if ( ai->ai_localdn.bv_val ) {
645 				ch_free( ai->ai_localdn.bv_val );
646 				ch_free( ai->ai_localndn.bv_val );
647 				BER_BVZERO( &ai->ai_localdn );
648 				BER_BVZERO( &ai->ai_localndn );
649 			}
650 			break;
651 		/* single-valued attrs, all no-ops */
652 		}
653 		break;
654 	case SLAP_CONFIG_ADD:
655 	case LDAP_MOD_ADD:
656 		switch( c->type ) {
657 		case ACA_USRCLASS:
658 			{
659 				ObjectClass *oc = oc_find( c->value_string );
660 				if ( oc )
661 					ai->ai_usrclass = oc;
662 				else
663 					rc = 1;
664 			}
665 			break;
666 		case ACA_SRVCLASS:
667 			{
668 				ObjectClass *oc = oc_find( c->value_string );
669 				if ( oc )
670 					ai->ai_srvclass = oc;
671 				else
672 					rc = 1;
673 			}
674 		case ACA_USRKEYBITS:
675 			if ( c->value_int < MIN_KEYBITS )
676 				rc = 1;
677 			else
678 				ai->ai_usrkeybits = c->value_int;
679 			break;
680 		case ACA_SRVKEYBITS:
681 			if ( c->value_int < MIN_KEYBITS )
682 				rc = 1;
683 			else
684 				ai->ai_srvkeybits = c->value_int;
685 			break;
686 		case ACA_CAKEYBITS:
687 			if ( c->value_int < MIN_KEYBITS )
688 				rc = 1;
689 			else
690 				ai->ai_cakeybits = c->value_int;
691 			break;
692 		case ACA_USRDAYS:
693 			ai->ai_usrdays = c->value_int;
694 			break;
695 		case ACA_SRVDAYS:
696 			ai->ai_srvdays = c->value_int;
697 			break;
698 		case ACA_CADAYS:
699 			ai->ai_cadays = c->value_int;
700 			break;
701 		case ACA_LOCALDN:
702 			if ( c->be->be_nsuffix == NULL ) {
703 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
704 					"suffix must be set" );
705 				Debug( LDAP_DEBUG_CONFIG, "autoca_config: %s\n",
706 					c->cr_msg );
707 				rc = ARG_BAD_CONF;
708 				break;
709 			}
710 			if ( !dnIsSuffix( &c->value_ndn, c->be->be_nsuffix )) {
711 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
712 					"DN is not a subordinate of backend" );
713 				Debug( LDAP_DEBUG_CONFIG, "autoca_config: %s\n",
714 					c->cr_msg );
715 				rc = ARG_BAD_CONF;
716 				break;
717 			}
718 			if ( ai->ai_localdn.bv_val ) {
719 				ch_free( ai->ai_localdn.bv_val );
720 				ch_free( ai->ai_localndn.bv_val );
721 			}
722 			ai->ai_localdn = c->value_dn;
723 			ai->ai_localndn = c->value_ndn;
724 		}
725 	}
726 	return rc;
727 }
728 
729 static ConfigTable autoca_cfg[] = {
730 	{ "userClass", "objectclass", 2, 2, 0,
731 	  ARG_STRING|ARG_MAGIC|ACA_USRCLASS, autoca_cf,
732 	  "( OLcfgOvAt:22.1 NAME 'olcAutoCAuserClass' "
733 	  "DESC 'ObjectClass of user entries' "
734 	  "EQUALITY caseIgnoreMatch "
735 	  "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
736 	{ "serverClass", "objectclass", 2, 2, 0,
737 	  ARG_STRING|ARG_MAGIC|ACA_SRVCLASS, autoca_cf,
738 	  "( OLcfgOvAt:22.2 NAME 'olcAutoCAserverClass' "
739 	  "DESC 'ObjectClass of server entries' "
740 	  "EQUALITY caseIgnoreMatch "
741 	  "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
742 	{ "userKeybits", "integer", 2, 2, 0,
743 	  ARG_INT|ARG_MAGIC|ACA_USRKEYBITS, autoca_cf,
744 	  "( OLcfgOvAt:22.3 NAME 'olcAutoCAuserKeybits' "
745 	  "DESC 'Size of PrivateKey for user entries' "
746 	  "EQUALITY integerMatch "
747 	  "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
748 	{ "serverKeybits", "integer", 2, 2, 0,
749 	  ARG_INT|ARG_MAGIC|ACA_SRVKEYBITS, autoca_cf,
750 	  "( OLcfgOvAt:22.4 NAME 'olcAutoCAserverKeybits' "
751 	  "DESC 'Size of PrivateKey for server entries' "
752 	  "EQUALITY integerMatch "
753 	  "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
754 	{ "caKeybits", "integer", 2, 2, 0,
755 	  ARG_INT|ARG_MAGIC|ACA_CAKEYBITS, autoca_cf,
756 	  "( OLcfgOvAt:22.5 NAME 'olcAutoCAKeybits' "
757 	  "DESC 'Size of PrivateKey for CA certificate' "
758 	  "EQUALITY integerMatch "
759 	  "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
760 	{ "userDays", "integer", 2, 2, 0,
761 	  ARG_INT|ARG_MAGIC|ACA_USRDAYS, autoca_cf,
762 	  "( OLcfgOvAt:22.6 NAME 'olcAutoCAuserDays' "
763 	  "DESC 'Lifetime of user certificates in days' "
764 	  "EQUALITY integerMatch "
765 	  "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
766 	{ "serverDays", "integer", 2, 2, 0,
767 	  ARG_INT|ARG_MAGIC|ACA_SRVDAYS, autoca_cf,
768 	  "( OLcfgOvAt:22.7 NAME 'olcAutoCAserverDays' "
769 	  "DESC 'Lifetime of server certificates in days' "
770 	  "EQUALITY integerMatch "
771 	  "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
772 	{ "caDays", "integer", 2, 2, 0,
773 	  ARG_INT|ARG_MAGIC|ACA_CADAYS, autoca_cf,
774 	  "( OLcfgOvAt:22.8 NAME 'olcAutoCADays' "
775 	  "DESC 'Lifetime of CA certificate in days' "
776 	  "EQUALITY integerMatch "
777 	  "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
778 	{ "localdn", "dn", 2, 2, 0,
779 	  ARG_DN|ARG_QUOTE|ARG_MAGIC|ACA_LOCALDN, autoca_cf,
780 	  "( OLcfgOvAt:22.9 NAME 'olcAutoCAlocalDN' "
781 	  "DESC 'DN of local server cert' "
782 	  "EQUALITY distinguishedNameMatch "
783 	  "SYNTAX OMsDN SINGLE-VALUE )", NULL, NULL },
784 	{ NULL, NULL, 0, 0, 0, ARG_IGNORED }
785 };
786 
787 static ConfigOCs autoca_ocs[] = {
788 	{ "( OLcfgOvOc:22.1 "
789 	  "NAME 'olcAutoCAConfig' "
790 	  "DESC 'AutoCA configuration' "
791 	  "SUP olcOverlayConfig "
792 	  "MAY ( olcAutoCAuserClass $ olcAutoCAserverClass $ "
793 	   "olcAutoCAuserKeybits $ olcAutoCAserverKeybits $ olcAutoCAKeyBits $ "
794 	   "olcAutoCAuserDays $ olcAutoCAserverDays $ olcAutoCADays $ "
795 	   "olcAutoCAlocalDN ) )",
796 	  Cft_Overlay, autoca_cfg },
797 	{ NULL, 0, NULL }
798 };
799 
800 static int
autoca_op_response(Operation * op,SlapReply * rs)801 autoca_op_response(
802 	Operation *op,
803 	SlapReply *rs
804 )
805 {
806 	slap_overinst *on = op->o_callback->sc_private;
807 	autoca_info *ai = on->on_bi.bi_private;
808 	Attribute *a;
809 	int isusr = 0;
810 
811 	if (rs->sr_type != REP_SEARCH)
812 		return SLAP_CB_CONTINUE;
813 
814 	/* If root or self */
815 	if ( !be_isroot( op ) &&
816 		!dn_match( &rs->sr_entry->e_nname, &op->o_ndn ))
817 		return SLAP_CB_CONTINUE;
818 
819 	isusr = is_entry_objectclass( rs->sr_entry, ai->ai_usrclass, SLAP_OCF_CHECK_SUP );
820 	if ( !isusr )
821 	{
822 		if (!is_entry_objectclass( rs->sr_entry, ai->ai_srvclass, SLAP_OCF_CHECK_SUP ))
823 			return SLAP_CB_CONTINUE;
824 	}
825 	a = attr_find( rs->sr_entry->e_attrs, ad_usrPkey );
826 	if ( !a )
827 	{
828 		Operation op2;
829 		genargs args;
830 		saveargs arg2;
831 		myext extras[2];
832 		int rc;
833 
834 		args.issuer_cert = ai->ai_cert;
835 		args.issuer_pkey = ai->ai_pkey;
836 		args.subjectDN = &rs->sr_entry->e_name;
837 		args.more_exts = NULL;
838 		if ( isusr )
839 		{
840 			args.cert_exts = usrExts;
841 			args.keybits = ai->ai_usrkeybits;
842 			args.days = ai->ai_usrdays;
843 			a = attr_find( rs->sr_entry->e_attrs, ad_mail );
844 			if ( a )
845 			{
846 				extras[0].name = "subjectAltName";
847 				extras[1].name = NULL;
848 				extras[0].value = op->o_tmpalloc( sizeof("email:") + a->a_vals[0].bv_len, op->o_tmpmemctx );
849 				sprintf(extras[0].value, "email:%s", a->a_vals[0].bv_val);
850 				args.more_exts = extras;
851 			}
852 		} else
853 		{
854 			args.cert_exts = srvExts;
855 			args.keybits = ai->ai_srvkeybits;
856 			args.days = ai->ai_srvdays;
857 			if ( ad_ipaddr && (a = attr_find( rs->sr_entry->e_attrs, ad_ipaddr )))
858 			{
859 				extras[0].name = "subjectAltName";
860 				extras[1].name = NULL;
861 				extras[0].value = op->o_tmpalloc( sizeof("IP:") + a->a_vals[0].bv_len, op->o_tmpmemctx );
862 				sprintf(extras[0].value, "IP:%s", a->a_vals[0].bv_val);
863 				args.more_exts = extras;
864 			}
865 		}
866 		rc = autoca_gencert( op, &args );
867 		if ( rc )
868 			return SLAP_CB_CONTINUE;
869 		X509_free( args.newcert );
870 		EVP_PKEY_free( args.newpkey );
871 
872 		if ( is_entry_objectclass( rs->sr_entry, oc_usrObj, 0 ))
873 			arg2.oc = NULL;
874 		else
875 			arg2.oc = oc_usrObj;
876 		if ( !( rs->sr_flags & REP_ENTRY_MODIFIABLE ))
877 		{
878 			Entry *e = entry_dup( rs->sr_entry );
879 			rs_replace_entry( op, rs, on, e );
880 			rs->sr_flags |= REP_ENTRY_MODIFIABLE | REP_ENTRY_MUSTBEFREED;
881 		}
882 		arg2.dercert = &args.dercert;
883 		arg2.derpkey = &args.derpkey;
884 		arg2.on = on;
885 		arg2.dn = &rs->sr_entry->e_name;
886 		arg2.ndn = &rs->sr_entry->e_nname;
887 		arg2.isca = 0;
888 		op2 = *op;
889 		rc = autoca_savecert( &op2, &arg2 );
890 		if ( !rc )
891 		{
892 			/* If this is our cert DN, configure it */
893 			if ( dn_match( &rs->sr_entry->e_nname, &ai->ai_localndn ))
894 				autoca_setlocal( &op2, &args.dercert, &args.derpkey );
895 			attr_merge_one( rs->sr_entry, ad_usrCert, &args.dercert, NULL );
896 			attr_merge_one( rs->sr_entry, ad_usrPkey, &args.derpkey, NULL );
897 		}
898 		op->o_tmpfree( args.dercert.bv_val, op->o_tmpmemctx );
899 		op->o_tmpfree( args.derpkey.bv_val, op->o_tmpmemctx );
900 	}
901 
902 	return SLAP_CB_CONTINUE;
903 }
904 
905 static int
autoca_op_search(Operation * op,SlapReply * rs)906 autoca_op_search(
907 	Operation *op,
908 	SlapReply *rs
909 )
910 {
911 	/* we only act on a search that returns just our cert/key attrs */
912 	if ( op->ors_attrs && op->ors_attrs[0].an_desc == ad_usrCert &&
913 		op->ors_attrs[1].an_desc == ad_usrPkey &&
914 		op->ors_attrs[2].an_name.bv_val == NULL )
915 	{
916 		slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
917 		slap_callback *sc = op->o_tmpcalloc( 1, sizeof(slap_callback), op->o_tmpmemctx );
918 		sc->sc_response = autoca_op_response;
919 		sc->sc_private = on;
920 		sc->sc_next = op->o_callback;
921 		op->o_callback = sc;
922 	}
923 	return SLAP_CB_CONTINUE;
924 }
925 
926 static int
autoca_db_init(BackendDB * be,ConfigReply * cr)927 autoca_db_init(
928 	BackendDB *be,
929 	ConfigReply *cr
930 )
931 {
932 	slap_overinst *on = (slap_overinst *) be->bd_info;
933 	autoca_info *ai;
934 
935 	ai = ch_calloc(1, sizeof(autoca_info));
936 	on->on_bi.bi_private = ai;
937 
938 	/* set defaults */
939 	ai->ai_usrclass = oc_find( "person" );
940 	ai->ai_srvclass = oc_find( "ipHost" );
941 	ai->ai_usrkeybits = KEYBITS;
942 	ai->ai_srvkeybits = KEYBITS;
943 	ai->ai_cakeybits = KEYBITS;
944 	ai->ai_usrdays = 365;	/* 1 year */
945 	ai->ai_srvdays = 1826;	/* 5 years */
946 	ai->ai_cadays = 3652;	/* 10 years */
947 	return 0;
948 }
949 
950 static int
autoca_db_destroy(BackendDB * be,ConfigReply * cr)951 autoca_db_destroy(
952 	BackendDB *be,
953 	ConfigReply *cr
954 )
955 {
956 	slap_overinst *on = (slap_overinst *) be->bd_info;
957 	autoca_info *ai = on->on_bi.bi_private;
958 
959 	if ( ai->ai_cert )
960 		X509_free( ai->ai_cert );
961 	if ( ai->ai_pkey )
962 		EVP_PKEY_free( ai->ai_pkey );
963 	ch_free( ai );
964 
965 	return 0;
966 }
967 
968 static int
autoca_db_open(BackendDB * be,ConfigReply * cr)969 autoca_db_open(
970 	BackendDB *be,
971 	ConfigReply *cr
972 )
973 {
974 	slap_overinst *on = (slap_overinst *)be->bd_info;
975 	autoca_info *ai = on->on_bi.bi_private;
976 
977 	Connection conn = { 0 };
978 	OperationBuffer opbuf;
979 	Operation *op;
980 	void *thrctx;
981 	Entry *e = NULL;
982 	Attribute *a;
983 	int rc;
984 
985 	if (slapMode & SLAP_TOOL_MODE)
986 		return 0;
987 
988 	if ( ! *aca_attr2[0].ad ) {
989 		int i, code;
990 		const char *text;
991 
992 		for ( i=0; aca_attr2[i].at; i++ ) {
993 			code = slap_str2ad( aca_attr2[i].at, aca_attr2[i].ad, &text );
994 			if ( code ) return code;
995 		}
996 
997 		/* Schema may not be loaded, ignore if missing */
998 		slap_str2ad( "ipHostNumber", &ad_ipaddr, &text );
999 
1000 		for ( i=0; aca_ocs[i].ot; i++ ) {
1001 			code = register_oc( aca_ocs[i].ot, aca_ocs[i].oc, 0 );
1002 			if ( code ) return code;
1003 		}
1004 	}
1005 
1006 	thrctx = ldap_pvt_thread_pool_context();
1007 	connection_fake_init2( &conn, &opbuf, thrctx, 0 );
1008 	op = &opbuf.ob_op;
1009 	op->o_bd = be;
1010 	op->o_dn = be->be_rootdn;
1011 	op->o_ndn = be->be_rootndn;
1012 	rc = overlay_entry_get_ov( op, be->be_nsuffix, NULL,
1013 		NULL, 0, &e, on );
1014 
1015 	if ( e ) {
1016 		int gotoc = 0, gotat = 0;
1017 		if ( is_entry_objectclass( e, oc_caObj, 0 )) {
1018 			gotoc = 1;
1019 			a = attr_find( e->e_attrs, ad_caPkey );
1020 			if ( a ) {
1021 				const unsigned char *pp;
1022 				pp = (unsigned char *)a->a_vals[0].bv_val;
1023 				ai->ai_pkey = d2i_AutoPrivateKey( NULL, &pp, a->a_vals[0].bv_len );
1024 				if ( ai->ai_pkey )
1025 				{
1026 					a = attr_find( e->e_attrs, ad_caCert );
1027 					if ( a )
1028 					{
1029 						pp = (unsigned char *)a->a_vals[0].bv_val;
1030 						ai->ai_cert = d2i_X509( NULL, &pp, a->a_vals[0].bv_len );
1031 						/* If TLS wasn't configured yet, set this as our CA */
1032 						if ( !slap_tls_ctx )
1033 							autoca_setca( a->a_vals );
1034 					}
1035 				}
1036 				gotat = 1;
1037 			}
1038 		}
1039 		overlay_entry_release_ov( op, e, 0, on );
1040 		/* generate attrs, store... */
1041 		if ( !gotat ) {
1042 			genargs args;
1043 			saveargs arg2;
1044 
1045 			args.issuer_cert = NULL;
1046 			args.issuer_pkey = NULL;
1047 			args.subjectDN = &be->be_suffix[0];
1048 			args.cert_exts = CAexts;
1049 			args.more_exts = NULL;
1050 			args.keybits = ai->ai_cakeybits;
1051 			args.days = ai->ai_cadays;
1052 
1053 			rc = autoca_gencert( op, &args );
1054 			if ( rc )
1055 				return -1;
1056 
1057 			ai->ai_cert = args.newcert;
1058 			ai->ai_pkey = args.newpkey;
1059 
1060 			arg2.dn = be->be_suffix;
1061 			arg2.ndn = be->be_nsuffix;
1062 			arg2.isca = 1;
1063 			if ( !gotoc )
1064 				arg2.oc = oc_caObj;
1065 			else
1066 				arg2.oc = NULL;
1067 			arg2.on = on;
1068 			arg2.dercert = &args.dercert;
1069 			arg2.derpkey = &args.derpkey;
1070 
1071 			autoca_savecert( op, &arg2 );
1072 
1073 			/* If TLS wasn't configured yet, set this as our CA */
1074 			if ( !slap_tls_ctx )
1075 				autoca_setca( &args.dercert );
1076 
1077 			op->o_tmpfree( args.dercert.bv_val, op->o_tmpmemctx );
1078 			op->o_tmpfree( args.derpkey.bv_val, op->o_tmpmemctx );
1079 		}
1080 	}
1081 
1082 	return 0;
1083 }
1084 
1085 static slap_overinst autoca;
1086 
1087 /* This overlay is set up for dynamic loading via moduleload. For static
1088  * configuration, you'll need to arrange for the slap_overinst to be
1089  * initialized and registered by some other function inside slapd.
1090  */
1091 
autoca_initialize()1092 int autoca_initialize() {
1093 	int i, code;
1094 
1095 	autoca.on_bi.bi_type = "autoca";
1096 	autoca.on_bi.bi_flags = SLAPO_BFLAG_SINGLE;
1097 	autoca.on_bi.bi_db_init = autoca_db_init;
1098 	autoca.on_bi.bi_db_destroy = autoca_db_destroy;
1099 	autoca.on_bi.bi_db_open = autoca_db_open;
1100 	autoca.on_bi.bi_op_search = autoca_op_search;
1101 
1102 	autoca.on_bi.bi_cf_ocs = autoca_ocs;
1103 	code = config_register_schema( autoca_cfg, autoca_ocs );
1104 	if ( code ) return code;
1105 
1106 	for ( i=0; aca_attrs[i]; i++ ) {
1107 		code = register_at( aca_attrs[i], NULL, 0 );
1108 		if ( code ) return code;
1109 	}
1110 
1111 	return overlay_register( &autoca );
1112 }
1113 
1114 #if SLAPD_OVER_AUTOCA == SLAPD_MOD_DYNAMIC
1115 int
init_module(int argc,char * argv[])1116 init_module( int argc, char *argv[] )
1117 {
1118 	return autoca_initialize();
1119 }
1120 #endif
1121 
1122 #endif /* defined(SLAPD_OVER_AUTOCA) */
1123