1 /* autoca.c - Automatic Certificate Authority */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 2009-2017 The OpenLDAP Foundation.
6 * Copyright 2009-2017 by Howard Chu.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted only as authorized by the OpenLDAP
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>.
18 * This work was initially developed by Howard Chu for inclusion in
24 #ifdef SLAPD_OVER_AUTOCA
28 #include <ac/string.h>
29 #include <ac/socket.h>
35 #include <openssl/x509.h>
36 #include <openssl/x509v3.h>
37 #include <openssl/evp.h>
38 #include <openssl/bn.h>
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
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)
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.
58 #define LBER_TAG_OID ((ber_tag_t) 0x06UL)
59 #define LBER_TAG_UTF8 ((ber_tag_t) 0x0cUL)
62 #define MIN_KEYBITS 512
64 #define ACA_SCHEMA_ROOT "1.3.6.1.4.1.4203.666.11.11"
66 #define ACA_SCHEMA_AT ACA_SCHEMA_ROOT ".1"
67 #define ACA_SCHEMA_OC ACA_SCHEMA_ROOT ".2"
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;
73 static char *aca_attrs[] = {
74 "( " ACA_SCHEMA_AT ".1 NAME 'cAPrivateKey' "
75 "DESC 'X.509 CA private key, use ;binary' "
76 "SUP x509PrivateKey )",
77 "( " ACA_SCHEMA_AT ".2 NAME 'userPrivateKey' "
78 "DESC 'X.509 user private key, use ;binary' "
79 "SUP x509PrivateKey )",
85 AttributeDescription **ad;
87 { "cACertificate;binary", &ad_caCert },
88 { "cAPrivateKey;binary", &ad_caPkey },
89 { "userCertificate;binary", &ad_usrCert },
90 { "userPrivateKey;binary", &ad_usrPkey },
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 },
110 typedef struct autoca_info {
113 ObjectClass *ai_usrclass;
114 ObjectClass *ai_srvclass;
115 struct berval ai_localdn;
116 struct berval ai_localndn;
125 /* Rewrite an LDAP DN in DER form
126 * Input must be valid DN, therefore no error checking is done here.
128 static int autoca_dnbv2der( Operation *op, struct berval *bv, struct berval *der )
130 BerElementBuffer berbuf;
131 BerElement *ber = (BerElement *)&berbuf;
135 AttributeDescription *ad;
138 ldap_bv2dn_x( bv, &dn, LDAP_DN_FORMAT_LDAP, op->o_tmpmemctx );
140 ber_init2( ber, NULL, LBER_USE_DER );
141 ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
143 /* count RDNs, we need them in reverse order */
144 for (irdn = 0; dn[irdn]; irdn++);
147 /* DN is a SEQuence of RDNs */
148 ber_start_seq( ber, LBER_SEQUENCE );
149 for (; irdn >=0; irdn--)
151 /* RDN is a SET of AVAs */
152 ber_start_set( ber, LBER_SET );
154 for (iava = 0; rdn[iava]; iava++)
158 struct berval bvo = { sizeof(oid), oid };
161 /* AVA is a SEQuence of attr and value */
162 ber_start_seq( ber, LBER_SEQUENCE );
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 );
175 ber_flatten2( ber, der, 0 );
176 ldap_dnfree_x( dn, op->o_tmpmemctx );
180 static int autoca_genpkey(int bits, EVP_PKEY **pkey)
185 kctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
188 if (EVP_PKEY_keygen_init(kctx) <= 0)
190 EVP_PKEY_CTX_free(kctx);
193 if (EVP_PKEY_CTX_set_rsa_keygen_bits(kctx, bits) <= 0)
195 EVP_PKEY_CTX_free(kctx);
198 rc = EVP_PKEY_keygen(kctx, pkey);
199 EVP_PKEY_CTX_free(kctx);
203 static int autoca_signcert(X509 *cert, EVP_PKEY *pkey)
205 EVP_MD_CTX *ctx = EVP_MD_CTX_create();
206 EVP_PKEY_CTX *pkctx = NULL;
211 if (EVP_DigestSignInit(ctx, &pkctx, NULL, NULL, pkey))
213 rc = X509_sign_ctx(cert, ctx);
215 EVP_MD_CTX_destroy(ctx);
219 #define SERIAL_BITS 64 /* should be less than 160 */
221 typedef struct myext {
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" },
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" },
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" },
255 typedef struct genargs {
257 EVP_PKEY *issuer_pkey;
258 struct berval *subjectDN;
263 struct berval dercert;
264 struct berval derpkey;
269 static int autoca_gencert( Operation *op, genargs *args )
271 X509_NAME *subj_name, *issuer_name;
275 EVP_PKEY *evpk = NULL;
278 if ((subj_cert = X509_new()) == NULL)
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 )
288 X509_free( subj_cert );
292 rc = autoca_genpkey( args->keybits, &evpk );
296 if ( subj_name ) X509_NAME_free( subj_name );
299 /* encode DER in PKCS#8 */
301 PKCS8_PRIV_KEY_INFO *p8inf;
302 if (( p8inf = EVP_PKEY2PKCS8( evpk )) == NULL )
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 );
310 args->newpkey = evpk;
312 /* set random serial */
314 BIGNUM *bn = BN_new();
318 EVP_PKEY_free( evpk );
321 if (!BN_pseudo_rand(bn, SERIAL_BITS, 0, 0))
326 if (!BN_to_ASN1_INTEGER(bn, X509_get_serialNumber(subj_cert)))
333 if (args->issuer_cert) {
334 issuer_name = X509_get_subject_name(args->issuer_cert);
336 issuer_name = subj_name;
337 args->issuer_cert = subj_cert;
338 args->issuer_pkey = evpk;
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))
349 X509_NAME_free(subj_name);
352 /* set cert extensions */
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);
363 rc = X509_add_ext(subj_cert, ext, -1);
364 X509_EXTENSION_free(ext);
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);
373 rc = X509_add_ext(subj_cert, ext, -1);
374 X509_EXTENSION_free(ext);
380 rc = autoca_signcert( subj_cert, args->issuer_pkey );
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;
391 typedef struct saveargs {
393 struct berval *dercert;
394 struct berval *derpkey;
401 static int autoca_savecert( Operation *op, saveargs *args )
403 Modifications mod[3], *mp = mod;
404 struct berval bvs[6], *bp = bvs;
406 slap_callback cb = {0};
407 SlapReply rs = {REP_RESULT};
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;
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;
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;
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;
458 static const struct berval configDN = BER_BVC("cn=config");
460 /* must run as a pool thread to avoid cn=config deadlock */
462 autoca_setca_task( void *ctx, void *arg )
464 Connection conn = { 0 };
465 OperationBuffer opbuf;
467 struct berval *cacert = arg;
469 struct berval bvs[2];
470 slap_callback cb = {0};
471 SlapReply rs = {REP_RESULT};
474 connection_fake_init( &conn, &opbuf, ctx );
478 mod.sml_values = bvs;
479 mod.sml_nvalues = NULL;
481 if ( slap_str2ad( "olcTLSCACertificate;binary", &mod.sml_desc, &text ))
483 mod.sml_op = LDAP_MOD_REPLACE;
484 mod.sml_flags = SLAP_MOD_INTERNAL;
486 BER_BVZERO( &bvs[1] );
489 cb.sc_response = slap_null_cb;
490 op->o_bd = select_backend( (struct berval *)&configDN, 0 );
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 );
509 autoca_setca( struct berval *cacert )
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 );
519 autoca_setlocal( Operation *op, struct berval *cert, struct berval *pkey )
521 Modifications mod[2];
522 struct berval bvs[4];
523 slap_callback cb = {0};
524 SlapReply rs = {REP_RESULT};
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 ))
533 mod[0].sml_op = LDAP_MOD_REPLACE;
534 mod[0].sml_flags = SLAP_MOD_INTERNAL;
536 BER_BVZERO( &bvs[1] );
537 mod[0].sml_next = &mod[1];
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 ))
545 mod[1].sml_op = LDAP_MOD_REPLACE;
546 mod[1].sml_flags = SLAP_MOD_INTERNAL;
548 BER_BVZERO( &bvs[3] );
549 mod[1].sml_next = NULL;
551 cb.sc_response = slap_null_cb;
552 op->o_bd = select_backend( (struct berval *)&configDN, 0 );
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 );
580 static int autoca_cf( ConfigArgs *c )
582 slap_overinst *on = (slap_overinst *)c->bi;
583 autoca_info *ai = on->on_bi.bi_private;
587 case SLAP_CONFIG_EMIT:
590 if ( ai->ai_usrclass ) {
591 c->value_string = ch_strdup( ai->ai_usrclass->soc_cname.bv_val );
597 if ( ai->ai_srvclass ) {
598 c->value_string = ch_strdup( ai->ai_srvclass->soc_cname.bv_val );
604 c->value_int = ai->ai_usrkeybits;
607 c->value_int = ai->ai_srvkeybits;
610 c->value_int = ai->ai_cakeybits;
613 c->value_int = ai->ai_usrdays;
616 c->value_int = ai->ai_srvdays;
619 c->value_int = ai->ai_cadays;
622 if ( !BER_BVISNULL( &ai->ai_localdn )) {
623 rc = value_add_one( &c->rvalue_vals, &ai->ai_localdn );
630 case LDAP_MOD_DELETE:
633 ai->ai_usrclass = NULL;
636 ai->ai_srvclass = NULL;
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 );
646 /* single-valued attrs, all no-ops */
649 case SLAP_CONFIG_ADD:
654 ObjectClass *oc = oc_find( c->value_string );
656 ai->ai_usrclass = oc;
663 ObjectClass *oc = oc_find( c->value_string );
665 ai->ai_srvclass = oc;
670 if ( c->value_int < MIN_KEYBITS )
673 ai->ai_usrkeybits = c->value_int;
676 if ( c->value_int < MIN_KEYBITS )
679 ai->ai_srvkeybits = c->value_int;
682 if ( c->value_int < MIN_KEYBITS )
685 ai->ai_cakeybits = c->value_int;
688 ai->ai_usrdays = c->value_int;
691 ai->ai_srvdays = c->value_int;
694 ai->ai_cadays = c->value_int;
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, NULL, NULL );
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, NULL, NULL );
713 if ( ai->ai_localdn.bv_val ) {
714 ch_free( ai->ai_localdn.bv_val );
715 ch_free( ai->ai_localndn.bv_val );
717 ai->ai_localdn = c->value_dn;
718 ai->ai_localndn = c->value_ndn;
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 'olcACAuserClass' "
728 "DESC 'ObjectClass of user entries' "
729 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
730 { "serverClass", "objectclass", 2, 2, 0,
731 ARG_STRING|ARG_MAGIC|ACA_SRVCLASS, autoca_cf,
732 "( OLcfgOvAt:22.2 NAME 'olcACAserverClass' "
733 "DESC 'ObjectClass of server entries' "
734 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
735 { "userKeybits", "integer", 2, 2, 0,
736 ARG_INT|ARG_MAGIC|ACA_USRKEYBITS, autoca_cf,
737 "( OLcfgOvAt:22.3 NAME 'olcACAuserKeybits' "
738 "DESC 'Size of PrivateKey for user entries' "
739 "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
740 { "serverKeybits", "integer", 2, 2, 0,
741 ARG_INT|ARG_MAGIC|ACA_SRVKEYBITS, autoca_cf,
742 "( OLcfgOvAt:22.4 NAME 'olcACAserverKeybits' "
743 "DESC 'Size of PrivateKey for server entries' "
744 "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
745 { "caKeybits", "integer", 2, 2, 0,
746 ARG_INT|ARG_MAGIC|ACA_CAKEYBITS, autoca_cf,
747 "( OLcfgOvAt:22.5 NAME 'olcACAKeybits' "
748 "DESC 'Size of PrivateKey for CA certificate' "
749 "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
750 { "userDays", "integer", 2, 2, 0,
751 ARG_INT|ARG_MAGIC|ACA_USRDAYS, autoca_cf,
752 "( OLcfgOvAt:22.6 NAME 'olcACAuserDays' "
753 "DESC 'Lifetime of user certificates in days' "
754 "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
755 { "serverDays", "integer", 2, 2, 0,
756 ARG_INT|ARG_MAGIC|ACA_SRVDAYS, autoca_cf,
757 "( OLcfgOvAt:22.7 NAME 'olcACAserverDays' "
758 "DESC 'Lifetime of server certificates in days' "
759 "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
760 { "caDays", "integer", 2, 2, 0,
761 ARG_INT|ARG_MAGIC|ACA_CADAYS, autoca_cf,
762 "( OLcfgOvAt:22.8 NAME 'olcACADays' "
763 "DESC 'Lifetime of CA certificate in days' "
764 "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
765 { "localdn", "dn", 2, 2, 0,
766 ARG_DN|ARG_MAGIC|ACA_LOCALDN, autoca_cf,
767 "( OLcfgOvAt:22.9 NAME 'olcACAlocalDN' "
768 "DESC 'DN of local server cert' "
769 "SYNTAX OMsDN SINGLE-VALUE )", NULL, NULL },
770 { NULL, NULL, 0, 0, 0, ARG_IGNORED }
773 static ConfigOCs autoca_ocs[] = {
774 { "( OLcfgOvOc:22.1 "
775 "NAME 'olcACAConfig' "
776 "DESC 'AutoCA configuration' "
777 "SUP olcOverlayConfig "
778 "MAY ( olcACAuserClass $ olcACAserverClass $ "
779 "olcACAuserKeybits $ olcACAserverKeybits $ olcACAKeyBits $ "
780 "olcACAuserDays $ olcACAserverDays $ olcACADays $ "
782 Cft_Overlay, autoca_cfg },
792 slap_overinst *on = op->o_callback->sc_private;
793 autoca_info *ai = on->on_bi.bi_private;
797 if (rs->sr_type != REP_SEARCH)
798 return SLAP_CB_CONTINUE;
800 /* If root or self */
801 if ( !be_isroot( op ) &&
802 !dn_match( &rs->sr_entry->e_nname, &op->o_ndn ))
803 return SLAP_CB_CONTINUE;
805 isusr = is_entry_objectclass( rs->sr_entry, ai->ai_usrclass, SLAP_OCF_CHECK_SUP );
808 if (!is_entry_objectclass( rs->sr_entry, ai->ai_srvclass, SLAP_OCF_CHECK_SUP ))
809 return SLAP_CB_CONTINUE;
811 a = attr_find( rs->sr_entry->e_attrs, ad_usrPkey );
820 args.issuer_cert = ai->ai_cert;
821 args.issuer_pkey = ai->ai_pkey;
822 args.subjectDN = &rs->sr_entry->e_name;
823 args.more_exts = NULL;
826 args.cert_exts = usrExts;
827 args.keybits = ai->ai_usrkeybits;
828 args.days = ai->ai_usrdays;
829 a = attr_find( rs->sr_entry->e_attrs, ad_mail );
832 extras[0].name = "subjectAltName";
833 extras[1].name = NULL;
834 extras[0].value = op->o_tmpalloc( sizeof("email:") + a->a_vals[0].bv_len, op->o_tmpmemctx );
835 sprintf(extras[0].value, "email:%s", a->a_vals[0].bv_val);
836 args.more_exts = extras;
840 args.cert_exts = srvExts;
841 args.keybits = ai->ai_srvkeybits;
842 args.days = ai->ai_srvdays;
843 if ( ad_ipaddr && (a = attr_find( rs->sr_entry->e_attrs, ad_ipaddr )))
845 extras[0].name = "subjectAltName";
846 extras[1].name = NULL;
847 extras[0].value = op->o_tmpalloc( sizeof("IP:") + a->a_vals[0].bv_len, op->o_tmpmemctx );
848 sprintf(extras[0].value, "IP:%s", a->a_vals[0].bv_val);
849 args.more_exts = extras;
852 rc = autoca_gencert( op, &args );
854 return SLAP_CB_CONTINUE;
855 X509_free( args.newcert );
856 EVP_PKEY_free( args.newpkey );
858 if ( is_entry_objectclass( rs->sr_entry, oc_usrObj, 0 ))
862 if ( !( rs->sr_flags & REP_ENTRY_MODIFIABLE ))
864 Entry *e = entry_dup( rs->sr_entry );
865 rs_replace_entry( op, rs, on, e );
866 rs->sr_flags |= REP_ENTRY_MODIFIABLE | REP_ENTRY_MUSTBEFREED;
868 arg2.dercert = &args.dercert;
869 arg2.derpkey = &args.derpkey;
871 arg2.dn = &rs->sr_entry->e_name;
872 arg2.ndn = &rs->sr_entry->e_nname;
875 rc = autoca_savecert( &op2, &arg2 );
878 /* If this is our cert DN, configure it */
879 if ( dn_match( &rs->sr_entry->e_nname, &ai->ai_localndn ))
880 autoca_setlocal( &op2, &args.dercert, &args.derpkey );
881 attr_merge_one( rs->sr_entry, ad_usrCert, &args.dercert, NULL );
882 attr_merge_one( rs->sr_entry, ad_usrPkey, &args.derpkey, NULL );
884 op->o_tmpfree( args.dercert.bv_val, op->o_tmpmemctx );
885 op->o_tmpfree( args.derpkey.bv_val, op->o_tmpmemctx );
888 return SLAP_CB_CONTINUE;
897 /* we only act on a search that returns just our cert/key attrs */
898 if ( op->ors_attrs && op->ors_attrs[0].an_desc == ad_usrCert &&
899 op->ors_attrs[1].an_desc == ad_usrPkey &&
900 op->ors_attrs[2].an_name.bv_val == NULL )
902 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
903 slap_callback *sc = op->o_tmpcalloc( 1, sizeof(slap_callback), op->o_tmpmemctx );
904 sc->sc_response = autoca_op_response;
906 sc->sc_next = op->o_callback;
909 return SLAP_CB_CONTINUE;
918 slap_overinst *on = (slap_overinst *) be->bd_info;
921 ai = ch_calloc(1, sizeof(autoca_info));
922 on->on_bi.bi_private = ai;
925 ai->ai_usrclass = oc_find( "person" );
926 ai->ai_srvclass = oc_find( "ipHost" );
927 ai->ai_usrkeybits = KEYBITS;
928 ai->ai_srvkeybits = KEYBITS;
929 ai->ai_cakeybits = KEYBITS;
930 ai->ai_usrdays = 365; /* 1 year */
931 ai->ai_srvdays = 1826; /* 5 years */
932 ai->ai_cadays = 3652; /* 10 years */
942 slap_overinst *on = (slap_overinst *) be->bd_info;
943 autoca_info *ai = on->on_bi.bi_private;
946 X509_free( ai->ai_cert );
948 EVP_PKEY_free( ai->ai_pkey );
960 slap_overinst *on = (slap_overinst *)be->bd_info;
961 autoca_info *ai = on->on_bi.bi_private;
963 Connection conn = { 0 };
964 OperationBuffer opbuf;
971 if (slapMode & SLAP_TOOL_MODE)
974 if ( ! *aca_attr2[0].ad ) {
978 for ( i=0; aca_attr2[i].at; i++ ) {
979 code = slap_str2ad( aca_attr2[i].at, aca_attr2[i].ad, &text );
980 if ( code ) return code;
983 /* Schema may not be loaded, ignore if missing */
984 slap_str2ad( "ipHostNumber", &ad_ipaddr, &text );
986 for ( i=0; aca_ocs[i].ot; i++ ) {
987 code = register_oc( aca_ocs[i].ot, aca_ocs[i].oc, 0 );
988 if ( code ) return code;
992 thrctx = ldap_pvt_thread_pool_context();
993 connection_fake_init2( &conn, &opbuf, thrctx, 0 );
996 op->o_dn = be->be_rootdn;
997 op->o_ndn = be->be_rootndn;
998 rc = overlay_entry_get_ov( op, be->be_nsuffix, NULL,
1002 int gotoc = 0, gotat = 0;
1003 if ( is_entry_objectclass( e, oc_caObj, 0 )) {
1005 a = attr_find( e->e_attrs, ad_caPkey );
1007 const unsigned char *pp;
1008 pp = (unsigned char *)a->a_vals[0].bv_val;
1009 ai->ai_pkey = d2i_AutoPrivateKey( NULL, &pp, a->a_vals[0].bv_len );
1012 a = attr_find( e->e_attrs, ad_caCert );
1015 pp = (unsigned char *)a->a_vals[0].bv_val;
1016 ai->ai_cert = d2i_X509( NULL, &pp, a->a_vals[0].bv_len );
1017 /* If TLS wasn't configured yet, set this as our CA */
1018 if ( !slap_tls_ctx )
1019 autoca_setca( a->a_vals );
1025 overlay_entry_release_ov( op, e, 0, on );
1026 /* generate attrs, store... */
1031 args.issuer_cert = NULL;
1032 args.issuer_pkey = NULL;
1033 args.subjectDN = &be->be_suffix[0];
1034 args.cert_exts = CAexts;
1035 args.more_exts = NULL;
1036 args.keybits = ai->ai_cakeybits;
1037 args.days = ai->ai_cadays;
1039 rc = autoca_gencert( op, &args );
1043 ai->ai_cert = args.newcert;
1044 ai->ai_pkey = args.newpkey;
1046 arg2.dn = be->be_suffix;
1047 arg2.ndn = be->be_nsuffix;
1054 arg2.dercert = &args.dercert;
1055 arg2.derpkey = &args.derpkey;
1057 autoca_savecert( op, &arg2 );
1059 /* If TLS wasn't configured yet, set this as our CA */
1060 if ( !slap_tls_ctx )
1061 autoca_setca( &args.dercert );
1063 op->o_tmpfree( args.dercert.bv_val, op->o_tmpmemctx );
1064 op->o_tmpfree( args.derpkey.bv_val, op->o_tmpmemctx );
1071 static slap_overinst autoca;
1073 /* This overlay is set up for dynamic loading via moduleload. For static
1074 * configuration, you'll need to arrange for the slap_overinst to be
1075 * initialized and registered by some other function inside slapd.
1078 int autoca_initialize() {
1081 autoca.on_bi.bi_type = "autoca";
1082 autoca.on_bi.bi_db_init = autoca_db_init;
1083 autoca.on_bi.bi_db_destroy = autoca_db_destroy;
1084 autoca.on_bi.bi_db_open = autoca_db_open;
1085 autoca.on_bi.bi_op_search = autoca_op_search;
1087 autoca.on_bi.bi_cf_ocs = autoca_ocs;
1088 code = config_register_schema( autoca_cfg, autoca_ocs );
1089 if ( code ) return code;
1091 for ( i=0; aca_attrs[i]; i++ ) {
1092 code = register_at( aca_attrs[i], NULL, 0 );
1093 if ( code ) return code;
1096 return overlay_register( &autoca );
1099 #if SLAPD_OVER_AUTOCA == SLAPD_MOD_DYNAMIC
1101 init_module( int argc, char *argv[] )
1103 return autoca_initialize();
1107 #endif /* defined(SLAPD_OVER_AUTOCA) */