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