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