]> git.sur5r.net Git - openldap/blob - servers/slapd/overlays/autoca.c
Add localDN config
[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         args->derpkey.bv_len = i2d_PrivateKey( evpk, NULL );
290         args->derpkey.bv_val = op->o_tmpalloc( args->derpkey.bv_len, op->o_tmpmemctx );
291         pp = args->derpkey.bv_val;
292         i2d_PrivateKey( evpk, &pp );
293         args->newpkey = evpk;
294
295         /* set random serial */
296         {
297                 BIGNUM *bn = BN_new();
298                 if ( bn == NULL )
299                 {
300 fail3:
301                         EVP_PKEY_free( evpk );
302                         goto fail2;
303                 }
304                 if (!BN_pseudo_rand(bn, SERIAL_BITS, 0, 0))
305                 {
306                         BN_free( bn );
307                         goto fail3;
308                 }
309                 if (!BN_to_ASN1_INTEGER(bn, X509_get_serialNumber(subj_cert)))
310                 {
311                         BN_free( bn );
312                         goto fail3;
313                 }
314                 BN_free(bn);
315         }
316         if (args->issuer_cert) {
317                 issuer_name = X509_get_subject_name(args->issuer_cert);
318         } else {
319                 issuer_name = subj_name;
320                 args->issuer_cert = subj_cert;
321                 args->issuer_pkey = evpk;
322         }
323         if (!X509_set_version(subj_cert, 2) ||  /* set version to V3 */
324                 !X509_set_issuer_name(subj_cert, issuer_name) ||
325                 !X509_set_subject_name(subj_cert, subj_name) ||
326                 !X509_gmtime_adj(X509_get_notBefore(subj_cert), 0) ||
327                 !X509_time_adj_ex(X509_get_notAfter(subj_cert), args->days, 0, NULL) ||
328                 !X509_set_pubkey(subj_cert, evpk))
329         {
330                 goto fail3;
331         }
332         X509_NAME_free(subj_name);
333         subj_name = NULL;
334
335         /* set cert extensions */
336         {
337                 X509V3_CTX ctx;
338                 X509_EXTENSION *ext;
339                 int i;
340
341                 X509V3_set_ctx(&ctx, args->issuer_cert, subj_cert, NULL, NULL, 0);
342                 for (i=0; args->cert_exts[i].name; i++) {
343                         ext = X509V3_EXT_nconf(NULL, &ctx, args->cert_exts[i].name, args->cert_exts[i].value);
344                         if ( ext == NULL )
345                                 goto fail3;
346                         rc = X509_add_ext(subj_cert, ext, -1);
347                         X509_EXTENSION_free(ext);
348                         if ( !rc )
349                                 goto fail3;
350                 }
351                 if (args->more_exts) {
352                         for (i=0; args->more_exts[i].name; i++) {
353                                 ext = X509V3_EXT_nconf(NULL, &ctx, args->more_exts[i].name, args->more_exts[i].value);
354                                 if ( ext == NULL )
355                                         goto fail3;
356                                 rc = X509_add_ext(subj_cert, ext, -1);
357                                 X509_EXTENSION_free(ext);
358                                 if ( !rc )
359                                         goto fail3;
360                         }
361                 }
362         }
363         rc = autoca_signcert( subj_cert, args->issuer_pkey );
364         if ( rc < 0 )
365                 goto fail3;
366         args->dercert.bv_len = i2d_X509( subj_cert, NULL );
367         args->dercert.bv_val = op->o_tmpalloc( args->dercert.bv_len, op->o_tmpmemctx );
368         pp = args->dercert.bv_val;
369         i2d_X509( subj_cert, &pp );
370         args->newcert = subj_cert;
371         return 0;
372 }
373
374 typedef struct saveargs {
375         ObjectClass *oc;
376         struct berval *dercert;
377         struct berval *derpkey;
378         slap_overinst *on;
379         struct berval *dn;
380         struct berval *ndn;
381         int isca;
382 } saveargs;
383
384 static int autoca_savecert( Operation *op, saveargs *args )
385 {
386         Modifications mod[3], *mp = mod;
387         struct berval bvs[6], *bp = bvs;
388         BackendInfo *bi;
389         slap_callback cb = {0};
390         SlapReply rs = {REP_RESULT};
391
392         if ( args->oc ) {
393                 mp->sml_numvals = 1;
394                 mp->sml_values = bp;
395                 mp->sml_nvalues = NULL;
396                 mp->sml_desc = slap_schema.si_ad_objectClass;
397                 mp->sml_op = LDAP_MOD_ADD;
398                 mp->sml_flags = SLAP_MOD_INTERNAL;
399                 *bp++ = args->oc->soc_cname;
400                 BER_BVZERO( bp );
401                 bp++;
402                 mp->sml_next = mp+1;
403                 mp++;
404         }
405         mp->sml_numvals = 1;
406         mp->sml_values = bp;
407         mp->sml_nvalues = NULL;
408         mp->sml_desc = args->isca ? ad_caCert : ad_usrCert;
409         mp->sml_op = LDAP_MOD_REPLACE;
410         mp->sml_flags = SLAP_MOD_INTERNAL;
411         *bp++ = *args->dercert;
412         BER_BVZERO( bp );
413         bp++;
414         mp->sml_next = mp+1;
415         mp++;
416
417         mp->sml_numvals = 1;
418         mp->sml_values = bp;
419         mp->sml_nvalues = NULL;
420         mp->sml_desc = args->isca ? ad_caPkey : ad_usrPkey;
421         mp->sml_op = LDAP_MOD_ADD;
422         mp->sml_flags = SLAP_MOD_INTERNAL;
423         *bp++ = *args->derpkey;
424         BER_BVZERO( bp );
425         mp->sml_next = NULL;
426
427         cb.sc_response = slap_null_cb;
428         bi = op->o_bd->bd_info;
429         op->o_bd->bd_info = args->on->on_info->oi_orig;
430         op->o_tag = LDAP_REQ_MODIFY;
431         op->o_callback = &cb;
432         op->orm_modlist = mod;
433         op->orm_no_opattrs = 1;
434         op->o_req_dn = *args->dn;
435         op->o_req_ndn = *args->ndn;
436         op->o_bd->be_modify( op, &rs );
437         op->o_bd->bd_info = bi;
438         return rs.sr_err;
439 }
440
441 static const struct berval configDN = BER_BVC("cn=config");
442
443 static int
444 autoca_setca( Operation *op, struct berval *cacert )
445 {
446         Operation op2;
447         Modifications mod;
448         struct berval bvs[2];
449         BackendInfo *bi;
450         slap_callback cb = {0};
451         SlapReply rs = {REP_RESULT};
452         const char *text;
453
454         op2 = *op;
455         mod.sml_numvals = 1;
456         mod.sml_values = bvs;
457         mod.sml_nvalues = NULL;
458         mod.sml_desc = NULL;
459         if ( slap_str2ad( "olcTLSCACertificate;binary", &mod.sml_desc, &text ))
460                 return -1;
461         mod.sml_op = LDAP_MOD_REPLACE;
462         mod.sml_flags = SLAP_MOD_INTERNAL;
463         bvs[0] = *cacert;
464         BER_BVZERO( &bvs[1] );
465         mod.sml_next = NULL;
466
467         cb.sc_response = slap_null_cb;
468         op2.o_bd = select_backend( (struct berval *)&configDN, 0 );
469         if ( !op2.o_bd )
470                 return -1;
471
472         op2.o_tag = LDAP_REQ_MODIFY;
473         op2.o_callback = &cb;
474         op2.orm_modlist = &mod;
475         op2.orm_no_opattrs = 1;
476         op2.o_req_dn = configDN;
477         op2.o_req_ndn = configDN;
478         op2.o_dn = op2.o_bd->be_rootdn;
479         op2.o_ndn = op2.o_bd->be_rootndn;
480         op2.o_bd->be_modify( &op2, &rs );
481         return rs.sr_err;
482 }
483
484 static int
485 autoca_setlocal( Operation *op, struct berval *cert, struct berval *pkey )
486 {
487         Modifications mod[2];
488         struct berval bvs[4];
489         BackendInfo *bi;
490         slap_callback cb = {0};
491         SlapReply rs = {REP_RESULT};
492         const char *text;
493         static const struct berval config = BER_BVC("cn=config");
494
495         mod[0].sml_numvals = 1;
496         mod[0].sml_values = bvs;
497         mod[0].sml_nvalues = NULL;
498         mod[0].sml_desc = NULL;
499         if ( slap_str2ad( "olcTLSCertificate;binary", &mod[0].sml_desc, &text ))
500                 return -1;
501         mod[0].sml_op = LDAP_MOD_REPLACE;
502         mod[0].sml_flags = SLAP_MOD_INTERNAL;
503         bvs[0] = *cert;
504         BER_BVZERO( &bvs[1] );
505         mod[0].sml_next = &mod[1];
506
507         mod[1].sml_numvals = 1;
508         mod[1].sml_values = &bvs[2];
509         mod[1].sml_nvalues = NULL;
510         mod[1].sml_desc = NULL;
511         if ( slap_str2ad( "olcTLSCertificateKey;binary", &mod[1].sml_desc, &text ))
512                 return -1;
513         mod[1].sml_op = LDAP_MOD_REPLACE;
514         mod[1].sml_flags = SLAP_MOD_INTERNAL;
515         bvs[2] = *pkey;
516         BER_BVZERO( &bvs[3] );
517         mod[1].sml_next = NULL;
518
519         cb.sc_response = slap_null_cb;
520         op->o_bd = select_backend( (struct berval *)&configDN, 0 );
521         if ( !op->o_bd )
522                 return -1;
523
524         op->o_tag = LDAP_REQ_MODIFY;
525         op->o_callback = &cb;
526         op->orm_modlist = mod;
527         op->orm_no_opattrs = 1;
528         op->o_req_dn = configDN;
529         op->o_req_ndn = configDN;
530         op->o_dn = op->o_bd->be_rootdn;
531         op->o_ndn = op->o_bd->be_rootndn;
532         op->o_bd->be_modify( op, &rs );
533         return rs.sr_err;
534 }
535
536 enum {
537         ACA_USRCLASS = 1,
538         ACA_SRVCLASS,
539         ACA_USRKEYBITS,
540         ACA_SRVKEYBITS,
541         ACA_CAKEYBITS,
542         ACA_USRDAYS,
543         ACA_SRVDAYS,
544         ACA_CADAYS,
545         ACA_LOCALDN
546 };
547
548 static int autoca_cf( ConfigArgs *c )
549 {
550         slap_overinst *on = (slap_overinst *)c->bi;
551         autoca_info *ai = on->on_bi.bi_private;
552         int rc = 0;
553
554         switch( c->op ) {
555         case SLAP_CONFIG_EMIT:
556                 switch( c->type ) {
557                 case ACA_USRCLASS:
558                         if ( ai->ai_usrclass ) {
559                                 c->value_string = ch_strdup( ai->ai_usrclass->soc_cname.bv_val );
560                         } else {
561                                 rc = 1;
562                         }
563                         break;
564                 case ACA_SRVCLASS:
565                         if ( ai->ai_srvclass ) {
566                                 c->value_string = ch_strdup( ai->ai_srvclass->soc_cname.bv_val );
567                         } else {
568                                 rc = 1;
569                         }
570                         break;
571                 case ACA_USRKEYBITS:
572                         c->value_int = ai->ai_usrkeybits;
573                         break;
574                 case ACA_SRVKEYBITS:
575                         c->value_int = ai->ai_srvkeybits;
576                         break;
577                 case ACA_CAKEYBITS:
578                         c->value_int = ai->ai_cakeybits;
579                         break;
580                 case ACA_USRDAYS:
581                         c->value_int = ai->ai_usrdays;
582                         break;
583                 case ACA_SRVDAYS:
584                         c->value_int = ai->ai_srvdays;
585                         break;
586                 case ACA_CADAYS:
587                         c->value_int = ai->ai_cadays;
588                         break;
589                 case ACA_LOCALDN:
590                         if ( !BER_BVISNULL( &ai->ai_localdn )) {
591                                 rc = value_add_one( &c->rvalue_vals, &ai->ai_localdn );
592                         } else {
593                                 rc = 1;
594                         }
595                         break;
596                 }
597                 break;
598         case LDAP_MOD_DELETE:
599                 switch( c->type ) {
600                 case ACA_USRCLASS:
601                         ai->ai_usrclass = NULL;
602                         break;
603                 case ACA_SRVCLASS:
604                         ai->ai_srvclass = NULL;
605                         break;
606                 case ACA_LOCALDN:
607                         if ( ai->ai_localdn.bv_val ) {
608                                 ch_free( ai->ai_localdn.bv_val );
609                                 ch_free( ai->ai_localndn.bv_val );
610                                 BER_BVZERO( &ai->ai_localdn );
611                                 BER_BVZERO( &ai->ai_localndn );
612                         }
613                         break;
614                 /* single-valued attrs, all no-ops */
615                 }
616                 break;
617         case SLAP_CONFIG_ADD:
618         case LDAP_MOD_ADD:
619                 switch( c->type ) {
620                 case ACA_USRCLASS:
621                         {
622                                 ObjectClass *oc = oc_find( c->value_string );
623                                 if ( oc )
624                                         ai->ai_usrclass = oc;
625                                 else
626                                         rc = 1;
627                         }
628                         break;
629                 case ACA_SRVCLASS:
630                         {
631                                 ObjectClass *oc = oc_find( c->value_string );
632                                 if ( oc )
633                                         ai->ai_srvclass = oc;
634                                 else
635                                         rc = 1;
636                         }
637                 case ACA_USRKEYBITS:
638                         if ( c->value_int < MIN_KEYBITS )
639                                 rc = 1;
640                         else
641                                 ai->ai_usrkeybits = c->value_int;
642                         break;
643                 case ACA_SRVKEYBITS:
644                         if ( c->value_int < MIN_KEYBITS )
645                                 rc = 1;
646                         else
647                                 ai->ai_srvkeybits = c->value_int;
648                         break;
649                 case ACA_CAKEYBITS:
650                         if ( c->value_int < MIN_KEYBITS )
651                                 rc = 1;
652                         else
653                                 ai->ai_cakeybits = c->value_int;
654                         break;
655                 case ACA_USRDAYS:
656                         ai->ai_usrdays = c->value_int;
657                         break;
658                 case ACA_SRVDAYS:
659                         ai->ai_srvdays = c->value_int;
660                         break;
661                 case ACA_CADAYS:
662                         ai->ai_cadays = c->value_int;
663                         break;
664                 case ACA_LOCALDN:
665                         if ( c->be->be_nsuffix == NULL ) {
666                                 snprintf( c->cr_msg, sizeof( c->cr_msg ),
667                                         "suffix must be set" );
668                                 Debug( LDAP_DEBUG_CONFIG, "autoca_config: %s\n",
669                                         c->cr_msg, NULL, NULL );
670                                 rc = ARG_BAD_CONF;
671                                 break;
672                         }
673                         if ( !dnIsSuffix( &c->value_ndn, c->be->be_nsuffix )) {
674                                 snprintf( c->cr_msg, sizeof( c->cr_msg ),
675                                         "DN is not a subordinate of backend" );
676                                 Debug( LDAP_DEBUG_CONFIG, "autoca_config: %s\n",
677                                         c->cr_msg, NULL, NULL );
678                                 rc = ARG_BAD_CONF;
679                                 break;
680                         }
681                         if ( ai->ai_localdn.bv_val ) {
682                                 ch_free( ai->ai_localdn.bv_val );
683                                 ch_free( ai->ai_localndn.bv_val );
684                         }
685                         ai->ai_localdn = c->value_dn;
686                         ai->ai_localndn = c->value_ndn;
687                 }
688         }
689         return rc;
690 }
691
692 static ConfigTable autoca_cfg[] = {
693         { "userClass", "objectclass", 2, 2, 0,
694           ARG_STRING|ARG_MAGIC|ACA_USRCLASS, autoca_cf,
695           "( OLcfgOvAt:22.1 NAME 'olcACAuserClass' "
696           "DESC 'ObjectClass of user entries' "
697           "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
698         { "serverClass", "objectclass", 2, 2, 0,
699           ARG_STRING|ARG_MAGIC|ACA_SRVCLASS, autoca_cf,
700           "( OLcfgOvAt:22.2 NAME 'olcACAserverClass' "
701           "DESC 'ObjectClass of server entries' "
702           "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
703         { "userKeybits", "integer", 2, 2, 0,
704           ARG_INT|ARG_MAGIC|ACA_USRKEYBITS, autoca_cf,
705           "( OLcfgOvAt:22.3 NAME 'olcACAuserKeybits' "
706           "DESC 'Size of PrivateKey for user entries' "
707           "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
708         { "serverKeybits", "integer", 2, 2, 0,
709           ARG_INT|ARG_MAGIC|ACA_SRVKEYBITS, autoca_cf,
710           "( OLcfgOvAt:22.4 NAME 'olcACAserverKeybits' "
711           "DESC 'Size of PrivateKey for server entries' "
712           "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
713         { "caKeybits", "integer", 2, 2, 0,
714           ARG_INT|ARG_MAGIC|ACA_CAKEYBITS, autoca_cf,
715           "( OLcfgOvAt:22.5 NAME 'olcACAKeybits' "
716           "DESC 'Size of PrivateKey for CA certificate' "
717           "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
718         { "userDays", "integer", 2, 2, 0,
719           ARG_INT|ARG_MAGIC|ACA_USRDAYS, autoca_cf,
720           "( OLcfgOvAt:22.6 NAME 'olcACAuserDays' "
721           "DESC 'Lifetime of user certificates in days' "
722           "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
723         { "serverDays", "integer", 2, 2, 0,
724           ARG_INT|ARG_MAGIC|ACA_SRVDAYS, autoca_cf,
725           "( OLcfgOvAt:22.7 NAME 'olcACAserverDays' "
726           "DESC 'Lifetime of server certificates in days' "
727           "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
728         { "caDays", "integer", 2, 2, 0,
729           ARG_INT|ARG_MAGIC|ACA_CADAYS, autoca_cf,
730           "( OLcfgOvAt:22.8 NAME 'olcACADays' "
731           "DESC 'Lifetime of CA certificate in days' "
732           "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
733         { "localdn", "dn", 2, 2, 0,
734           ARG_DN|ARG_MAGIC|ACA_LOCALDN, autoca_cf,
735           "( OLcfgOvAt:22.9 NAME 'olcACAlocalDN' "
736           "DESC 'DN of local server cert' "
737           "SYNTAX OMsDN SINGLE-VALUE )", NULL, NULL },
738         { NULL, NULL, 0, 0, 0, ARG_IGNORED }
739 };
740
741 static ConfigOCs autoca_ocs[] = {
742         { "( OLcfgOvOc:22.1 "
743           "NAME 'olcACAConfig' "
744           "DESC 'AutoCA configuration' "
745           "SUP olcOverlayConfig "
746           "MAY ( olcACAuserClass $ olcACAserverClass $ "
747            "olcACAuserKeybits $ olcACAserverKeybits $ olcACAKeyBits $ "
748            "olcACAuserDays $ olcACAserverDays $ olcACADays $ "
749            "olcACAlocalDN ) )",
750           Cft_Overlay, autoca_cfg },
751         { NULL, 0, NULL }
752 };
753
754 static int
755 autoca_op_response(
756         Operation *op,
757         SlapReply *rs
758 )
759 {
760         slap_overinst *on = op->o_callback->sc_private;
761         autoca_info *ai = on->on_bi.bi_private;
762         Attribute *a;
763         int isusr = 0;
764
765         if (rs->sr_type != REP_SEARCH)
766                 return SLAP_CB_CONTINUE;
767
768         /* If root or self */
769         if ( !be_isroot( op ) &&
770                 !dn_match( &rs->sr_entry->e_nname, &op->o_ndn ))
771                 return SLAP_CB_CONTINUE;
772
773         isusr = is_entry_objectclass( rs->sr_entry, ai->ai_usrclass, SLAP_OCF_CHECK_SUP );
774         if ( !isusr )
775         {
776                 if (!is_entry_objectclass( rs->sr_entry, ai->ai_srvclass, SLAP_OCF_CHECK_SUP ))
777                         return SLAP_CB_CONTINUE;
778         }
779         a = attr_find( rs->sr_entry->e_attrs, ad_usrPkey );
780         if ( !a )
781         {
782                 Operation op2;
783                 genargs args;
784                 saveargs arg2;
785                 myext extras[2];
786                 int rc;
787
788                 args.issuer_cert = ai->ai_cert;
789                 args.issuer_pkey = ai->ai_pkey;
790                 args.subjectDN = &rs->sr_entry->e_name;
791                 args.more_exts = NULL;
792                 if ( isusr )
793                 {
794                         args.cert_exts = usrExts;
795                         args.keybits = ai->ai_usrkeybits;
796                         args.days = ai->ai_usrdays;
797                         a = attr_find( rs->sr_entry->e_attrs, ad_mail );
798                         if ( a )
799                         {
800                                 extras[0].name = "subjectAltName";
801                                 extras[1].name = NULL;
802                                 extras[0].value = op->o_tmpalloc( sizeof("email:") + a->a_vals[0].bv_len, op->o_tmpmemctx );
803                                 sprintf(extras[0].value, "email:%s", a->a_vals[0].bv_val);
804                                 args.more_exts = extras;
805                         }
806                 } else
807                 {
808                         args.cert_exts = srvExts;
809                         args.keybits = ai->ai_srvkeybits;
810                         args.days = ai->ai_srvdays;
811                         if ( ad_ipaddr && (a = attr_find( rs->sr_entry->e_attrs, ad_ipaddr )))
812                         {
813                                 extras[0].name = "subjectAltName";
814                                 extras[1].name = NULL;
815                                 extras[0].value = op->o_tmpalloc( sizeof("IP:") + a->a_vals[0].bv_len, op->o_tmpmemctx );
816                                 sprintf(extras[0].value, "IP:%s", a->a_vals[0].bv_val);
817                                 args.more_exts = extras;
818                         }
819                 }
820                 rc = autoca_gencert( op, &args );
821                 if ( rc )
822                         return SLAP_CB_CONTINUE;
823                 X509_free( args.newcert );
824                 EVP_PKEY_free( args.newpkey );
825
826                 if ( is_entry_objectclass( rs->sr_entry, oc_usrObj, 0 ))
827                         arg2.oc = NULL;
828                 else
829                         arg2.oc = oc_usrObj;
830                 arg2.dercert = &args.dercert;
831                 arg2.derpkey = &args.derpkey;
832                 arg2.on = on;
833                 arg2.dn = &rs->sr_entry->e_name;
834                 arg2.ndn = &rs->sr_entry->e_nname;
835                 arg2.isca = 0;
836                 op2 = *op;
837                 rc = autoca_savecert( &op2, &arg2 );
838                 if ( !rc )
839                 {
840                         /* If this is our cert DN, configure it */
841                         if ( dn_match( &rs->sr_entry->e_nname, &ai->ai_localndn ))
842                                 autoca_setlocal( &op2, &args.dercert, &args.derpkey );
843                         if ( !( rs->sr_flags & REP_ENTRY_MODIFIABLE ))
844                         {
845                                 Entry *e = entry_dup( rs->sr_entry );
846                                 rs_replace_entry( op, rs, on, e );
847                                 rs->sr_flags |= REP_ENTRY_MODIFIABLE | REP_ENTRY_MUSTBEFREED;
848                         }
849                         attr_merge_one( rs->sr_entry, ad_usrCert, &args.dercert, NULL );
850                         attr_merge_one( rs->sr_entry, ad_usrPkey, &args.derpkey, NULL );
851                 }
852                 op->o_tmpfree( args.dercert.bv_val, op->o_tmpmemctx );
853                 op->o_tmpfree( args.derpkey.bv_val, op->o_tmpmemctx );
854         }
855
856         return SLAP_CB_CONTINUE;
857 }
858
859 static int
860 autoca_op_search(
861         Operation *op,
862         SlapReply *rs
863 )
864 {
865         /* we only act on a search that returns just our cert/key attrs */
866         if ( op->ors_attrs[0].an_desc == ad_usrCert &&
867                 op->ors_attrs[1].an_desc == ad_usrPkey &&
868                 op->ors_attrs[2].an_name.bv_val == NULL )
869         {
870                 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
871                 slap_callback *sc = op->o_tmpcalloc( 1, sizeof(slap_callback), op->o_tmpmemctx );
872                 sc->sc_response = autoca_op_response;
873                 sc->sc_private = on;
874                 sc->sc_next = op->o_callback;
875                 op->o_callback = sc;
876         }
877         return SLAP_CB_CONTINUE;
878 }
879
880 static int
881 autoca_db_init(
882         BackendDB *be,
883         ConfigReply *cr
884 )
885 {
886         slap_overinst *on = (slap_overinst *) be->bd_info;
887         autoca_info *ai;
888
889         ai = ch_calloc(1, sizeof(autoca_info));
890         on->on_bi.bi_private = ai;
891
892         /* set defaults */
893         ai->ai_usrclass = oc_find( "person" );
894         ai->ai_srvclass = oc_find( "ipHost" );
895         ai->ai_usrkeybits = KEYBITS;
896         ai->ai_srvkeybits = KEYBITS;
897         ai->ai_cakeybits = KEYBITS;
898         ai->ai_usrdays = 365;   /* 1 year */
899         ai->ai_srvdays = 1826;  /* 5 years */
900         ai->ai_cadays = 3652;   /* 10 years */
901         return 0;
902 }
903
904 static int
905 autoca_db_destroy(
906         BackendDB *be,
907         ConfigReply *cr
908 )
909 {
910         slap_overinst *on = (slap_overinst *) be->bd_info;
911         autoca_info *ai = on->on_bi.bi_private;
912
913         if ( ai->ai_cert )
914                 X509_free( ai->ai_cert );
915         if ( ai->ai_pkey )
916                 EVP_PKEY_free( ai->ai_pkey );
917         ch_free( ai );
918
919         return 0;
920 }
921
922 static int
923 autoca_db_open(
924         BackendDB *be,
925         ConfigReply *cr
926 )
927 {
928         slap_overinst *on = (slap_overinst *)be->bd_info;
929         autoca_info *ai = on->on_bi.bi_private;
930
931         Connection conn = { 0 };
932         OperationBuffer opbuf;
933         Operation *op;
934         void *thrctx;
935         Entry *e;
936         Attribute *a;
937         int rc;
938
939         if (slapMode & SLAP_TOOL_MODE)
940                 return 0;
941
942         thrctx = ldap_pvt_thread_pool_context();
943         connection_fake_init2( &conn, &opbuf, thrctx, 0 );
944         op = &opbuf.ob_op;
945         op->o_bd = be;
946         op->o_dn = be->be_rootdn;
947         op->o_ndn = be->be_rootndn;
948         rc = overlay_entry_get_ov( op, be->be_nsuffix, NULL, 
949                 NULL, 0, &e, on );
950
951         if ( e ) {
952                 int gotoc = 0, gotat = 0;
953                 if ( is_entry_objectclass( e, oc_caObj, 0 )) {
954                         gotoc = 1;
955                         a = attr_find( e->e_attrs, ad_caPkey );
956                         if ( a ) {
957                                 const unsigned char *pp;
958                                 pp = a->a_vals[0].bv_val;
959                                 ai->ai_pkey = d2i_AutoPrivateKey( NULL, &pp, a->a_vals[0].bv_len );
960                                 if ( ai->ai_pkey )
961                                 {
962                                         a = attr_find( e->e_attrs, ad_caCert );
963                                         if ( a )
964                                         {
965                                                 pp = a->a_vals[0].bv_val;
966                                                 ai->ai_cert = d2i_X509( NULL, &pp, a->a_vals[0].bv_len );
967                                                 /* If TLS wasn't configured yet, set this as our CA */
968                                                 if ( !slap_tls_ctx )
969                                                         autoca_setca( op, a->a_vals );
970                                         }
971                                 }
972                                 gotat = 1;
973                         }
974                 }
975                 overlay_entry_release_ov( op, e, 0, on );
976                 /* generate attrs, store... */
977                 if ( !gotat ) {
978                         genargs args;
979                         saveargs arg2;
980
981                         args.issuer_cert = NULL;
982                         args.issuer_pkey = NULL;
983                         args.subjectDN = &be->be_suffix[0];
984                         args.cert_exts = CAexts;
985                         args.more_exts = NULL;
986                         args.keybits = ai->ai_cakeybits;
987                         args.days = ai->ai_cadays;
988
989                         rc = autoca_gencert( op, &args );
990                         if ( rc )
991                                 return -1;
992
993                         ai->ai_cert = args.newcert;
994                         ai->ai_pkey = args.newpkey;
995
996                         arg2.dn = be->be_suffix;
997                         arg2.ndn = be->be_nsuffix;
998                         arg2.isca = 1;
999                         if ( !gotoc )
1000                                 arg2.oc = oc_caObj;
1001                         else
1002                                 arg2.oc = NULL;
1003                         arg2.on = on;
1004                         arg2.dercert = &args.dercert;
1005                         arg2.derpkey = &args.derpkey;
1006
1007                         autoca_savecert( op, &arg2 );
1008
1009                         /* If TLS wasn't configured yet, set this as our CA */
1010                         if ( !slap_tls_ctx )
1011                                 autoca_setca( op, &args.dercert );
1012
1013                         op->o_tmpfree( args.dercert.bv_val, op->o_tmpmemctx );
1014                         op->o_tmpfree( args.derpkey.bv_val, op->o_tmpmemctx );
1015                 }
1016         }
1017
1018         return 0;
1019 }
1020
1021 static slap_overinst autoca;
1022
1023 /* This overlay is set up for dynamic loading via moduleload. For static
1024  * configuration, you'll need to arrange for the slap_overinst to be
1025  * initialized and registered by some other function inside slapd.
1026  */
1027
1028 int autoca_initialize() {
1029         int i, code;
1030         const char *text;
1031
1032         autoca.on_bi.bi_type = "autoca";
1033         autoca.on_bi.bi_db_init = autoca_db_init;
1034         autoca.on_bi.bi_db_destroy = autoca_db_destroy;
1035         autoca.on_bi.bi_db_open = autoca_db_open;
1036         autoca.on_bi.bi_op_search = autoca_op_search;
1037
1038         autoca.on_bi.bi_cf_ocs = autoca_ocs;
1039         code = config_register_schema( autoca_cfg, autoca_ocs );
1040         if ( code ) return code;
1041
1042         for ( i=0; aca_attrs[i]; i++ ) {
1043                 code = register_at( aca_attrs[i], NULL, 0 );
1044                 if ( code ) return code;
1045         }
1046
1047         for ( i=0; aca_attr2[i].at; i++ ) {
1048                 code = slap_str2ad( aca_attr2[i].at, aca_attr2[i].ad, &text );
1049                 if ( code ) return code;
1050         }
1051
1052         /* Schema may not be loaded, ignore if missing */
1053         slap_str2ad( "ipHostNumber", &ad_ipaddr, &text );
1054
1055         for ( i=0; aca_ocs[i].ot; i++ ) {
1056                 code = register_oc( aca_ocs[i].ot, aca_ocs[i].oc, 0 );
1057                 if ( code ) return code;
1058         }
1059
1060         return overlay_register( &autoca );
1061 }
1062
1063 #if SLAPD_OVER_AUTOCA == SLAPD_MOD_DYNAMIC
1064 int
1065 init_module( int argc, char *argv[] )
1066 {
1067         return autoca_initialize();
1068 }
1069 #endif
1070
1071 #endif /* defined(SLAPD_OVER_AUTOCA) */