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 #define SLAPD_OVER_AUTOCA SLAPD_MOD_DYNAMIC
26 #ifdef SLAPD_OVER_AUTOCA
30 #include <ac/string.h>
31 #include <ac/socket.h>
37 #include <openssl/x509v3.h>
38 #include <openssl/evp.h>
40 /* This overlay implements a certificate authority that can generate
41 * certificates automatically for any entry in the directory.
42 * On startup it generates a self-signed CA cert for the directory's
43 * suffix entry and uses this to sign all other certs that it generates.
44 * User and server certs are generated on demand, using a Search request.
47 #define LBER_TAG_OID ((ber_tag_t) 0x06UL)
48 #define LBER_TAG_UTF8 ((ber_tag_t) 0x0cUL)
51 #define MIN_KEYBITS 512
53 #define ACA_SCHEMA_ROOT "1.3.6.1.4.1.4203.666.11.11"
55 #define ACA_SCHEMA_AT ACA_SCHEMA_ROOT ".1"
56 #define ACA_SCHEMA_OC ACA_SCHEMA_ROOT ".2"
58 static AttributeDescription *ad_caCert, *ad_caPkey, *ad_usrCert, *ad_usrPkey;
59 static AttributeDescription *ad_mail, *ad_ipaddr;
60 static ObjectClass *oc_caObj, *oc_usrObj;
62 static char *aca_attrs[] = {
63 "( " ACA_SCHEMA_AT ".1 NAME 'cAPrivateKey' "
64 "DESC 'X.509 CA private key, use ;binary' "
65 "SUP x509PrivateKey )",
66 "( " ACA_SCHEMA_AT ".2 NAME 'userPrivateKey' "
67 "DESC 'X.509 user private key, use ;binary' "
68 "SUP x509PrivateKey )",
74 AttributeDescription **ad;
76 { "cACertificate;binary", &ad_caCert },
77 { "cAPrivateKey;binary", &ad_caPkey },
78 { "userCertificate;binary", &ad_usrCert },
79 { "userPrivateKey;binary", &ad_usrPkey },
88 { "( " ACA_SCHEMA_OC ".1 NAME 'autoCA' "
89 "DESC 'Automated PKI certificate authority' "
90 "SUP pkiCA AUXILIARY "
91 "MAY cAPrivateKey )", &oc_caObj },
92 { "( " ACA_SCHEMA_OC ".2 NAME 'autoCAuser' "
93 "DESC 'Automated PKI CA user' "
94 "SUP pkiUser AUXILIARY "
95 "MAY userPrivateKey )", &oc_usrObj },
99 typedef struct autoca_info {
102 ObjectClass *ai_usrclass;
103 ObjectClass *ai_srvclass;
112 /* Rewrite an LDAP DN in DER form
113 * Input must be valid DN, therefore no error checking is done here.
115 static int autoca_dnbv2der( Operation *op, struct berval *bv, struct berval *der )
117 BerElementBuffer berbuf;
118 BerElement *ber = (BerElement *)&berbuf;
122 AttributeDescription *ad;
125 ldap_bv2dn_x( bv, &dn, LDAP_DN_FORMAT_LDAP, op->o_tmpmemctx );
127 ber_init2( ber, NULL, LBER_USE_DER );
128 ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
130 /* count RDNs, we need them in reverse order */
131 for (irdn = 0; dn[irdn]; irdn++);
134 /* DN is a SEQuence of RDNs */
135 ber_start_seq( ber, LBER_SEQUENCE );
136 for (; irdn >=0; irdn--)
138 /* RDN is a SET of AVAs */
139 ber_start_set( ber, LBER_SET );
141 for (iava = 0; rdn[iava]; iava++)
145 struct berval bvo = { sizeof(oid), oid };
148 /* AVA is a SEQuence of attr and value */
149 ber_start_seq( ber, LBER_SEQUENCE );
152 slap_bv2ad( &ava->la_attr, &ad, &text );
153 ber_str2bv( ad->ad_type->sat_oid, 0, 0, &bva );
154 ber_encode_oid( &bva, &bvo );
155 ber_put_berval( ber, &bvo, LBER_TAG_OID );
156 ber_put_berval( ber, &ava->la_value, LBER_TAG_UTF8 );
162 ber_flatten2( ber, der, 0 );
163 ldap_dnfree_x( dn, op->o_tmpmemctx );
167 static int autoca_genpkey(int bits, EVP_PKEY **pkey)
172 kctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
175 if (EVP_PKEY_keygen_init(kctx) <= 0)
177 EVP_PKEY_CTX_free(kctx);
180 if (EVP_PKEY_CTX_set_rsa_keygen_bits(kctx, bits) <= 0)
182 EVP_PKEY_CTX_free(kctx);
185 rc = EVP_PKEY_keygen(kctx, pkey);
186 EVP_PKEY_CTX_free(kctx);
190 static int autoca_signcert(X509 *cert, EVP_PKEY *pkey)
192 EVP_MD_CTX *ctx = EVP_MD_CTX_create();
193 EVP_PKEY_CTX *pkctx = NULL;
198 if (EVP_DigestSignInit(ctx, &pkctx, NULL, NULL, pkey))
200 rc = X509_sign_ctx(cert, ctx);
202 EVP_MD_CTX_destroy(ctx);
206 #define SERIAL_BITS 64 /* should be less than 160 */
208 typedef struct myext {
213 static myext CAexts[] = {
214 { "subjectKeyIdentifier", "hash" },
215 { "authorityKeyIdentifier", "keyid:always,issuer" },
216 { "basicConstraints", "critical,CA:true" },
217 { "keyUsage", "digitalSignature,cRLSign,keyCertSign" },
218 { "nsComment", "OpenLDAP automatic certificate" },
222 static myext usrExts[] = {
223 { "subjectKeyIdentifier", "hash" },
224 { "authorityKeyIdentifier", "keyid:always,issuer" },
225 { "basicConstraints", "CA:false" },
226 { "keyUsage", "digitalSignature,nonRepudiation,keyEncipherment" },
227 { "extendedKeyUsage", "clientAuth,emailProtection,codeSigning" },
228 { "nsComment", "OpenLDAP automatic certificate" },
232 static myext srvExts[] = {
233 { "subjectKeyIdentifier", "hash" },
234 { "authorityKeyIdentifier", "keyid:always,issuer" },
235 { "basicConstraints", "CA:false" },
236 { "keyUsage", "digitalSignature,keyEncipherment" },
237 { "extendedKeyUsage", "serverAuth,clientAuth" },
238 { "nsComment", "OpenLDAP automatic certificate" },
242 typedef struct genargs {
244 EVP_PKEY *issuer_pkey;
245 struct berval *subjectDN;
250 struct berval dercert;
251 struct berval derpkey;
256 static int autoca_gencert( Operation *op, genargs *args )
258 X509_NAME *subj_name, *issuer_name;
261 const unsigned char *p;
262 EVP_PKEY *evpk = NULL;
266 if ((subj_cert = X509_new()) == NULL)
269 autoca_dnbv2der( op, args->subjectDN, &derdn );
270 p = (const unsigned char *)derdn.bv_val;
271 subj_name = d2i_X509_NAME( NULL, &p, derdn.bv_len );
272 op->o_tmpfree( derdn.bv_val, op->o_tmpmemctx );
273 if ( subj_name == NULL )
276 X509_free( subj_cert );
280 rc = autoca_genpkey( args->keybits, &evpk );
284 if ( subj_name ) X509_NAME_free( subj_name );
287 args->derpkey.bv_len = i2d_PrivateKey( evpk, NULL );
288 args->derpkey.bv_val = op->o_tmpalloc( args->derpkey.bv_len, op->o_tmpmemctx );
289 pp = args->derpkey.bv_val;
290 i2d_PrivateKey( evpk, &pp );
291 args->newpkey = evpk;
293 /* set random serial */
295 BIGNUM *bn = BN_new();
299 EVP_PKEY_free( evpk );
302 if (!BN_pseudo_rand(bn, SERIAL_BITS, 0, 0))
307 if (!BN_to_ASN1_INTEGER(bn, X509_get_serialNumber(subj_cert)))
314 if (args->issuer_cert) {
315 issuer_name = X509_get_subject_name(args->issuer_cert);
317 issuer_name = subj_name;
318 args->issuer_cert = subj_cert;
319 args->issuer_pkey = evpk;
321 if (!X509_set_version(subj_cert, 2) || /* set version to V3 */
322 !X509_set_issuer_name(subj_cert, issuer_name) ||
323 !X509_set_subject_name(subj_cert, subj_name) ||
324 !X509_gmtime_adj(X509_get_notBefore(subj_cert), 0) ||
325 !X509_time_adj_ex(X509_get_notAfter(subj_cert), args->days, 0, NULL) ||
326 !X509_set_pubkey(subj_cert, evpk))
330 X509_NAME_free(subj_name);
333 /* set cert extensions */
339 X509V3_set_ctx(&ctx, args->issuer_cert, subj_cert, NULL, NULL, 0);
340 for (i=0; args->cert_exts[i].name; i++) {
341 ext = X509V3_EXT_nconf(NULL, &ctx, args->cert_exts[i].name, args->cert_exts[i].value);
344 rc = X509_add_ext(subj_cert, ext, -1);
345 X509_EXTENSION_free(ext);
349 if (args->more_exts) {
350 for (i=0; args->more_exts[i].name; i++) {
351 ext = X509V3_EXT_nconf(NULL, &ctx, args->more_exts[i].name, args->more_exts[i].value);
354 rc = X509_add_ext(subj_cert, ext, -1);
355 X509_EXTENSION_free(ext);
361 rc = autoca_signcert( subj_cert, args->issuer_pkey );
364 args->dercert.bv_len = i2d_X509( subj_cert, NULL );
365 args->dercert.bv_val = op->o_tmpalloc( args->dercert.bv_len, op->o_tmpmemctx );
366 pp = args->dercert.bv_val;
367 i2d_X509( subj_cert, &pp );
368 args->newcert = subj_cert;
372 typedef struct saveargs {
374 struct berval *dercert;
375 struct berval *derpkey;
382 static int autoca_savecert( Operation *op, saveargs *args )
384 Modifications mod[3], *mp = mod;
385 struct berval bvs[6], *bp = bvs;
387 slap_callback cb = {0};
388 SlapReply rs = {REP_RESULT};
393 mp->sml_nvalues = NULL;
394 mp->sml_desc = slap_schema.si_ad_objectClass;
395 mp->sml_op = LDAP_MOD_ADD;
396 mp->sml_flags = SLAP_MOD_INTERNAL;
397 *bp++ = args->oc->soc_cname;
405 mp->sml_nvalues = NULL;
406 mp->sml_desc = args->isca ? ad_caCert : ad_usrCert;
407 mp->sml_op = LDAP_MOD_REPLACE;
408 mp->sml_flags = SLAP_MOD_INTERNAL;
409 *bp++ = *args->dercert;
417 mp->sml_nvalues = NULL;
418 mp->sml_desc = args->isca ? ad_caPkey : ad_usrPkey;
419 mp->sml_op = LDAP_MOD_ADD;
420 mp->sml_flags = SLAP_MOD_INTERNAL;
421 *bp++ = *args->derpkey;
425 cb.sc_response = slap_null_cb;
426 bi = op->o_bd->bd_info;
427 op->o_bd->bd_info = args->on->on_info->oi_orig;
428 op->o_tag = LDAP_REQ_MODIFY;
429 op->o_callback = &cb;
430 op->orm_modlist = mod;
431 op->orm_no_opattrs = 1;
432 op->o_req_dn = *args->dn;
433 op->o_req_ndn = *args->ndn;
434 op->o_bd->be_modify( op, &rs );
435 op->o_bd->bd_info = bi;
440 autoca_setca( Operation *op, struct berval *cacert )
444 struct berval bvs[2];
446 slap_callback cb = {0};
447 SlapReply rs = {REP_RESULT};
449 static const struct berval config = BER_BVC("cn=config");
453 mod.sml_values = bvs;
454 mod.sml_nvalues = NULL;
456 if ( slap_str2ad( "olcTLSCACertificate", &mod.sml_desc, &text ))
458 mod.sml_op = LDAP_MOD_REPLACE;
459 mod.sml_flags = SLAP_MOD_INTERNAL;
461 BER_BVZERO( &bvs[1] );
464 cb.sc_response = slap_null_cb;
465 op2.o_bd = select_backend( (struct berval *)&config, 0 );
469 op2.o_tag = LDAP_REQ_MODIFY;
470 op2.o_callback = &cb;
471 op2.orm_modlist = &mod;
472 op2.orm_no_opattrs = 1;
473 op2.o_req_dn = config;
474 op2.o_req_ndn = config;
475 op2.o_dn = op2.o_bd->be_rootdn;
476 op2.o_ndn = op2.o_bd->be_rootndn;
477 op2.o_bd->be_modify( &op2, &rs );
492 static int autoca_cf( ConfigArgs *c )
494 slap_overinst *on = (slap_overinst *)c->bi;
495 autoca_info *ai = on->on_bi.bi_private;
499 case SLAP_CONFIG_EMIT:
502 if ( ai->ai_usrclass ) {
503 c->value_string = ch_strdup( ai->ai_usrclass->soc_cname.bv_val );
509 if ( ai->ai_srvclass ) {
510 c->value_string = ch_strdup( ai->ai_srvclass->soc_cname.bv_val );
516 c->value_int = ai->ai_usrkeybits;
519 c->value_int = ai->ai_srvkeybits;
522 c->value_int = ai->ai_cakeybits;
525 c->value_int = ai->ai_usrdays;
528 c->value_int = ai->ai_srvdays;
531 c->value_int = ai->ai_cadays;
535 case LDAP_MOD_DELETE:
538 ai->ai_usrclass = NULL;
541 ai->ai_srvclass = NULL;
543 /* single-valued attrs, all no-ops */
546 case SLAP_CONFIG_ADD:
551 ObjectClass *oc = oc_find( c->value_string );
553 ai->ai_usrclass = oc;
560 ObjectClass *oc = oc_find( c->value_string );
562 ai->ai_srvclass = oc;
567 if ( c->value_int < MIN_KEYBITS )
570 ai->ai_usrkeybits = c->value_int;
573 if ( c->value_int < MIN_KEYBITS )
576 ai->ai_srvkeybits = c->value_int;
579 if ( c->value_int < MIN_KEYBITS )
582 ai->ai_cakeybits = c->value_int;
585 ai->ai_usrdays = c->value_int;
588 ai->ai_srvdays = c->value_int;
591 ai->ai_cadays = c->value_int;
598 static ConfigTable autoca_cfg[] = {
599 { "userClass", "objectclass", 2, 2, 0,
600 ARG_STRING|ARG_MAGIC|ACA_USRCLASS, autoca_cf,
601 "( OLcfgOvAt:22.1 NAME 'olcACAuserClass' "
602 "DESC 'ObjectClass of user entries' "
603 "SYNTAX OMsDirectoryString )", NULL, NULL },
604 { "servererClass", "objectclass", 2, 2, 0,
605 ARG_STRING|ARG_MAGIC|ACA_SRVCLASS, autoca_cf,
606 "( OLcfgOvAt:22.2 NAME 'olcACAserverClass' "
607 "DESC 'ObjectClass of server entries' "
608 "SYNTAX OMsDirectoryString )", NULL, NULL },
609 { "userKeybits", "integer", 2, 2, 0,
610 ARG_INT|ARG_MAGIC|ACA_USRKEYBITS, autoca_cf,
611 "( OLcfgOvAt:22.3 NAME 'olcACAuserKeybits' "
612 "DESC 'Size of PrivateKey for user entries' "
613 "SYNTAX OMsInteger )", NULL, NULL },
614 { "serverKeybits", "integer", 2, 2, 0,
615 ARG_INT|ARG_MAGIC|ACA_SRVKEYBITS, autoca_cf,
616 "( OLcfgOvAt:22.4 NAME 'olcACAserverKeybits' "
617 "DESC 'Size of PrivateKey for server entries' "
618 "SYNTAX OMsInteger )", NULL, NULL },
619 { "caKeybits", "integer", 2, 2, 0,
620 ARG_INT|ARG_MAGIC|ACA_CAKEYBITS, autoca_cf,
621 "( OLcfgOvAt:22.5 NAME 'olcACAKeybits' "
622 "DESC 'Size of PrivateKey for CA certificate' "
623 "SYNTAX OMsInteger )", NULL, NULL },
624 { "userDays", "integer", 2, 2, 0,
625 ARG_INT|ARG_MAGIC|ACA_USRDAYS, autoca_cf,
626 "( OLcfgOvAt:22.6 NAME 'olcACAuserDays' "
627 "DESC 'Lifetime of user certificates in days' "
628 "SYNTAX OMsInteger )", NULL, NULL },
629 { "serverDays", "integer", 2, 2, 0,
630 ARG_INT|ARG_MAGIC|ACA_SRVDAYS, autoca_cf,
631 "( OLcfgOvAt:22.7 NAME 'olcACAserverDays' "
632 "DESC 'Lifetime of server certificates in days' "
633 "SYNTAX OMsInteger )", NULL, NULL },
634 { "caDays", "integer", 2, 2, 0,
635 ARG_INT|ARG_MAGIC|ACA_CADAYS, autoca_cf,
636 "( OLcfgOvAt:22.8 NAME 'olcACADays' "
637 "DESC 'Lifetime of CA certificate in days' "
638 "SYNTAX OMsInteger )", NULL, NULL },
639 { NULL, NULL, 0, 0, 0, ARG_IGNORED }
642 static ConfigOCs autoca_ocs[] = {
643 { "( OLcfgOvOc:22.1 "
644 "NAME 'olcACAConfig' "
645 "DESC 'AutoCA configuration' "
646 "SUP olcOverlayConfig "
647 "MAY ( olcACAuserClass $ olcACAserverClass $ "
648 "olcACAuserKeybits $ olcACAserverKeybits $ olcACAKeyBits $ "
649 "olcACAuserDays $ olcACAserverDays $ olcACADays ) )",
650 Cft_Overlay, autoca_cfg },
660 slap_overinst *on = op->o_callback->sc_private;
661 autoca_info *ai = on->on_bi.bi_private;
665 if (rs->sr_type != REP_SEARCH)
666 return SLAP_CB_CONTINUE;
668 /* If root or self */
669 if ( !be_isroot( op ) &&
670 !dn_match( &rs->sr_entry->e_nname, &op->o_ndn ))
671 return SLAP_CB_CONTINUE;
673 isusr = is_entry_objectclass( rs->sr_entry, ai->ai_usrclass, SLAP_OCF_CHECK_SUP );
676 if (!is_entry_objectclass( rs->sr_entry, ai->ai_srvclass, SLAP_OCF_CHECK_SUP ))
677 return SLAP_CB_CONTINUE;
679 a = attr_find( rs->sr_entry->e_attrs, ad_usrPkey );
688 args.issuer_cert = ai->ai_cert;
689 args.issuer_pkey = ai->ai_pkey;
690 args.subjectDN = &rs->sr_entry->e_name;
691 args.more_exts = NULL;
694 args.cert_exts = usrExts;
695 args.keybits = ai->ai_usrkeybits;
696 args.days = ai->ai_usrdays;
697 a = attr_find( rs->sr_entry->e_attrs, ad_mail );
700 extras[0].name = "subjectAltName";
701 extras[1].name = NULL;
702 extras[0].value = op->o_tmpalloc( sizeof("email:") + a->a_vals[0].bv_len, op->o_tmpmemctx );
703 sprintf(extras[0].value, "email:%s", a->a_vals[0].bv_val);
704 args.more_exts = extras;
708 args.cert_exts = srvExts;
709 args.keybits = ai->ai_srvkeybits;
710 args.days = ai->ai_srvdays;
711 if ( ad_ipaddr && (a = attr_find( rs->sr_entry->e_attrs, ad_ipaddr )))
713 extras[0].name = "subjectAltName";
714 extras[1].name = NULL;
715 extras[0].value = op->o_tmpalloc( sizeof("IP:") + a->a_vals[0].bv_len, op->o_tmpmemctx );
716 sprintf(extras[0].value, "IP:%s", a->a_vals[0].bv_val);
717 args.more_exts = extras;
720 rc = autoca_gencert( op, &args );
722 return SLAP_CB_CONTINUE;
723 X509_free( args.newcert );
724 EVP_PKEY_free( args.newpkey );
726 if ( is_entry_objectclass( rs->sr_entry, oc_usrObj, 0 ))
730 arg2.dercert = &args.dercert;
731 arg2.derpkey = &args.derpkey;
733 arg2.dn = &rs->sr_entry->e_name;
734 arg2.ndn = &rs->sr_entry->e_nname;
737 rc = autoca_savecert( &op2, &arg2 );
740 if ( !( rs->sr_flags & REP_ENTRY_MODIFIABLE ))
742 Entry *e = entry_dup( rs->sr_entry );
743 rs_replace_entry( op, rs, on, e );
744 rs->sr_flags |= REP_ENTRY_MODIFIABLE | REP_ENTRY_MUSTBEFREED;
746 attr_merge_one( rs->sr_entry, ad_usrCert, &args.dercert, NULL );
747 attr_merge_one( rs->sr_entry, ad_usrPkey, &args.derpkey, NULL );
749 op->o_tmpfree( args.dercert.bv_val, op->o_tmpmemctx );
750 op->o_tmpfree( args.derpkey.bv_val, op->o_tmpmemctx );
753 return SLAP_CB_CONTINUE;
762 /* we only act on a search that returns just our cert/key attrs */
763 if ( op->ors_attrs[0].an_desc == ad_usrCert &&
764 op->ors_attrs[1].an_desc == ad_usrPkey &&
765 op->ors_attrs[2].an_name.bv_val == NULL )
767 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
768 slap_callback *sc = op->o_tmpcalloc( 1, sizeof(slap_callback), op->o_tmpmemctx );
769 sc->sc_response = autoca_op_response;
771 sc->sc_next = op->o_callback;
774 return SLAP_CB_CONTINUE;
783 slap_overinst *on = (slap_overinst *) be->bd_info;
786 ai = ch_calloc(1, sizeof(autoca_info));
787 on->on_bi.bi_private = ai;
790 ai->ai_usrclass = oc_find( "person" );
791 ai->ai_srvclass = oc_find( "ipHost" );
792 ai->ai_usrkeybits = KEYBITS;
793 ai->ai_srvkeybits = KEYBITS;
794 ai->ai_cakeybits = KEYBITS;
795 ai->ai_usrdays = 365; /* 1 year */
796 ai->ai_srvdays = 1826; /* 5 years */
797 ai->ai_cadays = 3652; /* 10 years */
807 slap_overinst *on = (slap_overinst *) be->bd_info;
808 autoca_info *ai = on->on_bi.bi_private;
811 X509_free( ai->ai_cert );
813 EVP_PKEY_free( ai->ai_pkey );
825 slap_overinst *on = (slap_overinst *)be->bd_info;
826 autoca_info *ai = on->on_bi.bi_private;
828 Connection conn = { 0 };
829 OperationBuffer opbuf;
836 if (slapMode & SLAP_TOOL_MODE)
839 thrctx = ldap_pvt_thread_pool_context();
840 connection_fake_init2( &conn, &opbuf, thrctx, 0 );
843 op->o_dn = be->be_rootdn;
844 op->o_ndn = be->be_rootndn;
845 rc = overlay_entry_get_ov( op, be->be_nsuffix, NULL,
849 int gotoc = 0, gotat = 0;
850 if ( is_entry_objectclass( e, oc_caObj, 0 )) {
852 a = attr_find( e->e_attrs, ad_caPkey );
854 const unsigned char *pp;
855 pp = a->a_vals[0].bv_val;
856 ai->ai_pkey = d2i_AutoPrivateKey( NULL, &pp, a->a_vals[0].bv_len );
859 a = attr_find( e->e_attrs, ad_caCert );
862 pp = a->a_vals[0].bv_val;
863 ai->ai_cert = d2i_X509( NULL, &pp, a->a_vals[0].bv_len );
864 /* If TLS wasn't configured yet, set this as our CA */
866 autoca_setca( op, a->a_vals );
872 overlay_entry_release_ov( op, e, 0, on );
873 /* generate attrs, store... */
878 args.issuer_cert = NULL;
879 args.issuer_pkey = NULL;
880 args.subjectDN = &be->be_suffix[0];
881 args.cert_exts = CAexts;
882 args.more_exts = NULL;
883 args.keybits = ai->ai_cakeybits;
884 args.days = ai->ai_cadays;
886 rc = autoca_gencert( op, &args );
890 ai->ai_cert = args.newcert;
891 ai->ai_pkey = args.newpkey;
893 arg2.dn = be->be_suffix;
894 arg2.ndn = be->be_nsuffix;
901 arg2.dercert = &args.dercert;
902 arg2.derpkey = &args.derpkey;
904 autoca_savecert( op, &arg2 );
906 /* If TLS wasn't configured yet, set this as our CA */
908 autoca_setca( op, &args.dercert );
910 op->o_tmpfree( args.dercert.bv_val, op->o_tmpmemctx );
911 op->o_tmpfree( args.derpkey.bv_val, op->o_tmpmemctx );
918 static slap_overinst autoca;
920 /* This overlay is set up for dynamic loading via moduleload. For static
921 * configuration, you'll need to arrange for the slap_overinst to be
922 * initialized and registered by some other function inside slapd.
925 int autoca_initialize() {
929 autoca.on_bi.bi_type = "autoca";
930 autoca.on_bi.bi_db_init = autoca_db_init;
931 autoca.on_bi.bi_db_destroy = autoca_db_destroy;
932 autoca.on_bi.bi_db_open = autoca_db_open;
933 autoca.on_bi.bi_op_search = autoca_op_search;
935 autoca.on_bi.bi_cf_ocs = autoca_ocs;
936 code = config_register_schema( autoca_cfg, autoca_ocs );
937 if ( code ) return code;
939 for ( i=0; aca_attrs[i]; i++ ) {
940 code = register_at( aca_attrs[i], NULL, 0 );
941 if ( code ) return code;
944 for ( i=0; aca_attr2[i].at; i++ ) {
945 code = slap_str2ad( aca_attr2[i].at, aca_attr2[i].ad, &text );
946 if ( code ) return code;
949 /* Schema may not be loaded, ignore if missing */
950 slap_str2ad( "ipHostNumber", &ad_ipaddr, &text );
952 for ( i=0; aca_ocs[i].ot; i++ ) {
953 code = register_oc( aca_ocs[i].ot, aca_ocs[i].oc, 0 );
954 if ( code ) return code;
957 return overlay_register( &autoca );
960 #if SLAPD_OVER_AUTOCA == SLAPD_MOD_DYNAMIC
962 init_module( int argc, char *argv[] )
964 return autoca_initialize();
968 #endif /* defined(SLAPD_OVER_AUTOCA) */