]> git.sur5r.net Git - openldap/blob - servers/slapd/overlays/autoca.c
07204bd0f3b4135461e87a39f0002dd39ac877c2
[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         int ai_usrkeybits;
105         int ai_srvkeybits;
106         int ai_cakeybits;
107         int ai_usrdays;
108         int ai_srvdays;
109         int ai_cadays;
110 } autoca_info;
111
112 /* Rewrite an LDAP DN in DER form
113  * Input must be valid DN, therefore no error checking is done here.
114  */
115 static int autoca_dnbv2der( Operation *op, struct berval *bv, struct berval *der )
116 {
117         BerElementBuffer berbuf;
118         BerElement *ber = (BerElement *)&berbuf;
119         LDAPDN dn;
120         LDAPRDN rdn;
121         LDAPAVA *ava;
122         AttributeDescription *ad;
123         int irdn, iava;
124
125         ldap_bv2dn_x( bv, &dn, LDAP_DN_FORMAT_LDAP, op->o_tmpmemctx );
126
127         ber_init2( ber, NULL, LBER_USE_DER );
128         ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
129
130         /* count RDNs, we need them in reverse order */
131         for (irdn = 0; dn[irdn]; irdn++);
132         irdn--;
133
134         /* DN is a SEQuence of RDNs */
135         ber_start_seq( ber, LBER_SEQUENCE );
136         for (; irdn >=0; irdn--)
137         {
138                 /* RDN is a SET of AVAs */
139                 ber_start_set( ber, LBER_SET );
140                 rdn = dn[irdn];
141                 for (iava = 0; rdn[iava]; iava++)
142                 {
143                         const char *text;
144                         char oid[1024];
145                         struct berval bvo = { sizeof(oid), oid };
146                         struct berval bva;
147
148                         /* AVA is a SEQuence of attr and value */
149                         ber_start_seq( ber, LBER_SEQUENCE );
150                         ava = rdn[iava];
151                         ad = NULL;
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 );
157                         ber_put_seq( ber );
158                 }
159                 ber_put_set( ber );
160         }
161         ber_put_seq( ber );
162         ber_flatten2( ber, der, 0 );
163         ldap_dnfree_x( dn, op->o_tmpmemctx );
164         return 0;
165 }
166
167 static int autoca_genpkey(int bits, EVP_PKEY **pkey)
168 {
169         EVP_PKEY_CTX *kctx;
170         int rc;
171
172         kctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
173         if (kctx == NULL)
174                 return -1;
175         if (EVP_PKEY_keygen_init(kctx) <= 0)
176         {
177                 EVP_PKEY_CTX_free(kctx);
178                 return -1;
179         }
180         if (EVP_PKEY_CTX_set_rsa_keygen_bits(kctx, bits) <= 0)
181         {
182                 EVP_PKEY_CTX_free(kctx);
183                 return -1;
184         }
185         rc = EVP_PKEY_keygen(kctx, pkey);
186         EVP_PKEY_CTX_free(kctx);
187         return rc;
188 }
189
190 static int autoca_signcert(X509 *cert, EVP_PKEY *pkey)
191 {
192         EVP_MD_CTX *ctx = EVP_MD_CTX_create();
193         EVP_PKEY_CTX *pkctx = NULL;
194         int rc = -1;
195
196         if ( ctx == NULL )
197                 return -1;
198         if (EVP_DigestSignInit(ctx, &pkctx, NULL, NULL, pkey))
199         {
200                 rc = X509_sign_ctx(cert, ctx);
201         }
202         EVP_MD_CTX_destroy(ctx);
203         return rc;
204 }
205
206 #define SERIAL_BITS     64      /* should be less than 160 */
207
208 typedef struct myext {
209         char *name;
210         char *value;
211 } myext;
212
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" },
219         { NULL }
220 };
221
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" },
229         { NULL }
230 };
231
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" },
239         { NULL }
240 };
241
242 typedef struct genargs {
243         X509 *issuer_cert;
244         EVP_PKEY *issuer_pkey;
245         struct berval *subjectDN;
246         myext *cert_exts;
247         myext *more_exts;
248         X509 *newcert;
249         EVP_PKEY *newpkey;
250         struct berval dercert;
251         struct berval derpkey;
252         int keybits;
253         int days;
254 } genargs;
255
256 static int autoca_gencert( Operation *op, genargs *args )
257 {
258         X509_NAME *subj_name, *issuer_name;
259         X509 *subj_cert;
260         struct berval derdn;
261         const unsigned char *p;
262         EVP_PKEY *evpk = NULL;
263         int rc;
264         unsigned char *pp;
265
266         if ((subj_cert = X509_new()) == NULL)
267                 return -1;
268
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 )
274         {
275 fail1:
276                 X509_free( subj_cert );
277                 return -1;
278         }
279
280         rc = autoca_genpkey( args->keybits, &evpk );
281         if ( rc <= 0 )
282         {
283 fail2:
284                 if ( subj_name ) X509_NAME_free( subj_name );
285                 goto fail1;
286         }
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;
292
293         /* set random serial */
294         {
295                 BIGNUM *bn = BN_new();
296                 if ( bn == NULL )
297                 {
298 fail3:
299                         EVP_PKEY_free( evpk );
300                         goto fail2;
301                 }
302                 if (!BN_pseudo_rand(bn, SERIAL_BITS, 0, 0))
303                 {
304                         BN_free( bn );
305                         goto fail3;
306                 }
307                 if (!BN_to_ASN1_INTEGER(bn, X509_get_serialNumber(subj_cert)))
308                 {
309                         BN_free( bn );
310                         goto fail3;
311                 }
312                 BN_free(bn);
313         }
314         if (args->issuer_cert) {
315                 issuer_name = X509_get_subject_name(args->issuer_cert);
316         } else {
317                 issuer_name = subj_name;
318                 args->issuer_cert = subj_cert;
319                 args->issuer_pkey = evpk;
320         }
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))
327         {
328                 goto fail3;
329         }
330         X509_NAME_free(subj_name);
331         subj_name = NULL;
332
333         /* set cert extensions */
334         {
335                 X509V3_CTX ctx;
336                 X509_EXTENSION *ext;
337                 int i;
338
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);
342                         if ( ext == NULL )
343                                 goto fail3;
344                         rc = X509_add_ext(subj_cert, ext, -1);
345                         X509_EXTENSION_free(ext);
346                         if ( !rc )
347                                 goto fail3;
348                 }
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);
352                                 if ( ext == NULL )
353                                         goto fail3;
354                                 rc = X509_add_ext(subj_cert, ext, -1);
355                                 X509_EXTENSION_free(ext);
356                                 if ( !rc )
357                                         goto fail3;
358                         }
359                 }
360         }
361         rc = autoca_signcert( subj_cert, args->issuer_pkey );
362         if ( rc < 0 )
363                 goto fail3;
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;
369         return 0;
370 }
371
372 typedef struct saveargs {
373         ObjectClass *oc;
374         struct berval *dercert;
375         struct berval *derpkey;
376         slap_overinst *on;
377         struct berval *dn;
378         struct berval *ndn;
379         int isca;
380 } saveargs;
381
382 static int autoca_savecert( Operation *op, saveargs *args )
383 {
384         Modifications mod[3], *mp = mod;
385         struct berval bvs[6], *bp = bvs;
386         BackendInfo *bi;
387         slap_callback cb = {0};
388         SlapReply rs = {REP_RESULT};
389
390         if ( args->oc ) {
391                 mp->sml_numvals = 1;
392                 mp->sml_values = bp;
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;
398                 BER_BVZERO( bp );
399                 bp++;
400                 mp->sml_next = mp+1;
401                 mp++;
402         }
403         mp->sml_numvals = 1;
404         mp->sml_values = bp;
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;
410         BER_BVZERO( bp );
411         bp++;
412         mp->sml_next = mp+1;
413         mp++;
414
415         mp->sml_numvals = 1;
416         mp->sml_values = bp;
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;
422         BER_BVZERO( bp );
423         mp->sml_next = NULL;
424
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;
436         return rs.sr_err;
437 }
438
439 static int
440 autoca_setca( Operation *op, struct berval *cacert )
441 {
442         Operation op2;
443         Modifications mod;
444         struct berval bvs[2];
445         BackendInfo *bi;
446         slap_callback cb = {0};
447         SlapReply rs = {REP_RESULT};
448         const char *text;
449         static const struct berval config = BER_BVC("cn=config");
450
451         op2 = *op;
452         mod.sml_numvals = 1;
453         mod.sml_values = bvs;
454         mod.sml_nvalues = NULL;
455         mod.sml_desc = NULL;
456         if ( slap_str2ad( "olcTLSCACertificate", &mod.sml_desc, &text ))
457                 return -1;
458         mod.sml_op = LDAP_MOD_REPLACE;
459         mod.sml_flags = SLAP_MOD_INTERNAL;
460         bvs[0] = *cacert;
461         BER_BVZERO( &bvs[1] );
462         mod.sml_next = NULL;
463
464         cb.sc_response = slap_null_cb;
465         op2.o_bd = select_backend( (struct berval *)&config, 0 );
466         if ( !op2.o_bd )
467                 return -1;
468
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 );
478         return rs.sr_err;
479 }
480
481 enum {
482         ACA_USRCLASS = 1,
483         ACA_SRVCLASS,
484         ACA_USRKEYBITS,
485         ACA_SRVKEYBITS,
486         ACA_CAKEYBITS,
487         ACA_USRDAYS,
488         ACA_SRVDAYS,
489         ACA_CADAYS
490 };
491
492 static int autoca_cf( ConfigArgs *c )
493 {
494         slap_overinst *on = (slap_overinst *)c->bi;
495         autoca_info *ai = on->on_bi.bi_private;
496         int rc = 0;
497
498         switch( c->op ) {
499         case SLAP_CONFIG_EMIT:
500                 switch( c->type ) {
501                 case ACA_USRCLASS:
502                         if ( ai->ai_usrclass ) {
503                                 c->value_string = ch_strdup( ai->ai_usrclass->soc_cname.bv_val );
504                         } else {
505                                 rc = 1;
506                         }
507                         break;
508                 case ACA_SRVCLASS:
509                         if ( ai->ai_srvclass ) {
510                                 c->value_string = ch_strdup( ai->ai_srvclass->soc_cname.bv_val );
511                         } else {
512                                 rc = 1;
513                         }
514                         break;
515                 case ACA_USRKEYBITS:
516                         c->value_int = ai->ai_usrkeybits;
517                         break;
518                 case ACA_SRVKEYBITS:
519                         c->value_int = ai->ai_srvkeybits;
520                         break;
521                 case ACA_CAKEYBITS:
522                         c->value_int = ai->ai_cakeybits;
523                         break;
524                 case ACA_USRDAYS:
525                         c->value_int = ai->ai_usrdays;
526                         break;
527                 case ACA_SRVDAYS:
528                         c->value_int = ai->ai_srvdays;
529                         break;
530                 case ACA_CADAYS:
531                         c->value_int = ai->ai_cadays;
532                         break;
533                 }
534                 break;
535         case LDAP_MOD_DELETE:
536                 switch( c->type ) {
537                 case ACA_USRCLASS:
538                         ai->ai_usrclass = NULL;
539                         break;
540                 case ACA_SRVCLASS:
541                         ai->ai_srvclass = NULL;
542                         break;
543                 /* single-valued attrs, all no-ops */
544                 }
545                 break;
546         case SLAP_CONFIG_ADD:
547         case LDAP_MOD_ADD:
548                 switch( c->type ) {
549                 case ACA_USRCLASS:
550                         {
551                                 ObjectClass *oc = oc_find( c->value_string );
552                                 if ( oc )
553                                         ai->ai_usrclass = oc;
554                                 else
555                                         rc = 1;
556                         }
557                         break;
558                 case ACA_SRVCLASS:
559                         {
560                                 ObjectClass *oc = oc_find( c->value_string );
561                                 if ( oc )
562                                         ai->ai_srvclass = oc;
563                                 else
564                                         rc = 1;
565                         }
566                 case ACA_USRKEYBITS:
567                         if ( c->value_int < MIN_KEYBITS )
568                                 rc = 1;
569                         else
570                                 ai->ai_usrkeybits = c->value_int;
571                         break;
572                 case ACA_SRVKEYBITS:
573                         if ( c->value_int < MIN_KEYBITS )
574                                 rc = 1;
575                         else
576                                 ai->ai_srvkeybits = c->value_int;
577                         break;
578                 case ACA_CAKEYBITS:
579                         if ( c->value_int < MIN_KEYBITS )
580                                 rc = 1;
581                         else
582                                 ai->ai_cakeybits = c->value_int;
583                         break;
584                 case ACA_USRDAYS:
585                         ai->ai_usrdays = c->value_int;
586                         break;
587                 case ACA_SRVDAYS:
588                         ai->ai_srvdays = c->value_int;
589                         break;
590                 case ACA_CADAYS:
591                         ai->ai_cadays = c->value_int;
592                         break;
593                 }
594         }
595         return rc;
596 }
597
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 }
640 };
641
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 },
651         { NULL, 0, NULL }
652 };
653
654 static int
655 autoca_op_response(
656         Operation *op,
657         SlapReply *rs
658 )
659 {
660         slap_overinst *on = op->o_callback->sc_private;
661         autoca_info *ai = on->on_bi.bi_private;
662         Attribute *a;
663         int isusr = 0;
664
665         if (rs->sr_type != REP_SEARCH)
666                 return SLAP_CB_CONTINUE;
667
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;
672
673         isusr = is_entry_objectclass( rs->sr_entry, ai->ai_usrclass, SLAP_OCF_CHECK_SUP );
674         if ( !isusr )
675         {
676                 if (!is_entry_objectclass( rs->sr_entry, ai->ai_srvclass, SLAP_OCF_CHECK_SUP ))
677                         return SLAP_CB_CONTINUE;
678         }
679         a = attr_find( rs->sr_entry->e_attrs, ad_usrPkey );
680         if ( !a )
681         {
682                 Operation op2;
683                 genargs args;
684                 saveargs arg2;
685                 myext extras[2];
686                 int rc;
687
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;
692                 if ( isusr )
693                 {
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 );
698                         if ( a )
699                         {
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;
705                         }
706                 } else
707                 {
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 )))
712                         {
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;
718                         }
719                 }
720                 rc = autoca_gencert( op, &args );
721                 if ( rc )
722                         return SLAP_CB_CONTINUE;
723                 X509_free( args.newcert );
724                 EVP_PKEY_free( args.newpkey );
725
726                 if ( is_entry_objectclass( rs->sr_entry, oc_usrObj, 0 ))
727                         arg2.oc = NULL;
728                 else
729                         arg2.oc = oc_usrObj;
730                 arg2.dercert = &args.dercert;
731                 arg2.derpkey = &args.derpkey;
732                 arg2.on = on;
733                 arg2.dn = &rs->sr_entry->e_name;
734                 arg2.ndn = &rs->sr_entry->e_nname;
735                 arg2.isca = 0;
736                 op2 = *op;
737                 rc = autoca_savecert( &op2, &arg2 );
738                 if ( !rc )
739                 {
740                         if ( !( rs->sr_flags & REP_ENTRY_MODIFIABLE ))
741                         {
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;
745                         }
746                         attr_merge_one( rs->sr_entry, ad_usrCert, &args.dercert, NULL );
747                         attr_merge_one( rs->sr_entry, ad_usrPkey, &args.derpkey, NULL );
748                 }
749                 op->o_tmpfree( args.dercert.bv_val, op->o_tmpmemctx );
750                 op->o_tmpfree( args.derpkey.bv_val, op->o_tmpmemctx );
751         }
752
753         return SLAP_CB_CONTINUE;
754 }
755
756 static int
757 autoca_op_search(
758         Operation *op,
759         SlapReply *rs
760 )
761 {
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 )
766         {
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;
770                 sc->sc_private = on;
771                 sc->sc_next = op->o_callback;
772                 op->o_callback = sc;
773         }
774         return SLAP_CB_CONTINUE;
775 }
776
777 static int
778 autoca_db_init(
779         BackendDB *be,
780         ConfigReply *cr
781 )
782 {
783         slap_overinst *on = (slap_overinst *) be->bd_info;
784         autoca_info *ai;
785
786         ai = ch_calloc(1, sizeof(autoca_info));
787         on->on_bi.bi_private = ai;
788
789         /* set defaults */
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 */
798         return 0;
799 }
800
801 static int
802 autoca_db_destroy(
803         BackendDB *be,
804         ConfigReply *cr
805 )
806 {
807         slap_overinst *on = (slap_overinst *) be->bd_info;
808         autoca_info *ai = on->on_bi.bi_private;
809
810         if ( ai->ai_cert )
811                 X509_free( ai->ai_cert );
812         if ( ai->ai_pkey )
813                 EVP_PKEY_free( ai->ai_pkey );
814         ch_free( ai );
815
816         return 0;
817 }
818
819 static int
820 autoca_db_open(
821         BackendDB *be,
822         ConfigReply *cr
823 )
824 {
825         slap_overinst *on = (slap_overinst *)be->bd_info;
826         autoca_info *ai = on->on_bi.bi_private;
827
828         Connection conn = { 0 };
829         OperationBuffer opbuf;
830         Operation *op;
831         void *thrctx;
832         Entry *e;
833         Attribute *a;
834         int rc;
835
836         if (slapMode & SLAP_TOOL_MODE)
837                 return 0;
838
839         thrctx = ldap_pvt_thread_pool_context();
840         connection_fake_init2( &conn, &opbuf, thrctx, 0 );
841         op = &opbuf.ob_op;
842         op->o_bd = be;
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, 
846                 NULL, 0, &e, on );
847
848         if ( e ) {
849                 int gotoc = 0, gotat = 0;
850                 if ( is_entry_objectclass( e, oc_caObj, 0 )) {
851                         gotoc = 1;
852                         a = attr_find( e->e_attrs, ad_caPkey );
853                         if ( a ) {
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 );
857                                 if ( ai->ai_pkey )
858                                 {
859                                         a = attr_find( e->e_attrs, ad_caCert );
860                                         if ( a )
861                                         {
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 */
865                                                 if ( !slap_tls_ctx )
866                                                         autoca_setca( op, a->a_vals );
867                                         }
868                                 }
869                                 gotat = 1;
870                         }
871                 }
872                 overlay_entry_release_ov( op, e, 0, on );
873                 /* generate attrs, store... */
874                 if ( !gotat ) {
875                         genargs args;
876                         saveargs arg2;
877
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;
885
886                         rc = autoca_gencert( op, &args );
887                         if ( rc )
888                                 return -1;
889
890                         ai->ai_cert = args.newcert;
891                         ai->ai_pkey = args.newpkey;
892
893                         arg2.dn = be->be_suffix;
894                         arg2.ndn = be->be_nsuffix;
895                         arg2.isca = 1;
896                         if ( !gotoc )
897                                 arg2.oc = oc_caObj;
898                         else
899                                 arg2.oc = NULL;
900                         arg2.on = on;
901                         arg2.dercert = &args.dercert;
902                         arg2.derpkey = &args.derpkey;
903
904                         autoca_savecert( op, &arg2 );
905
906                         /* If TLS wasn't configured yet, set this as our CA */
907                         if ( !slap_tls_ctx )
908                                 autoca_setca( op, &args.dercert );
909
910                         op->o_tmpfree( args.dercert.bv_val, op->o_tmpmemctx );
911                         op->o_tmpfree( args.derpkey.bv_val, op->o_tmpmemctx );
912                 }
913         }
914
915         return 0;
916 }
917
918 static slap_overinst autoca;
919
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.
923  */
924
925 int autoca_initialize() {
926         int i, code;
927         const char *text;
928
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;
934
935         autoca.on_bi.bi_cf_ocs = autoca_ocs;
936         code = config_register_schema( autoca_cfg, autoca_ocs );
937         if ( code ) return code;
938
939         for ( i=0; aca_attrs[i]; i++ ) {
940                 code = register_at( aca_attrs[i], NULL, 0 );
941                 if ( code ) return code;
942         }
943
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;
947         }
948
949         /* Schema may not be loaded, ignore if missing */
950         slap_str2ad( "ipHostNumber", &ad_ipaddr, &text );
951
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;
955         }
956
957         return overlay_register( &autoca );
958 }
959
960 #if SLAPD_OVER_AUTOCA == SLAPD_MOD_DYNAMIC
961 int
962 init_module( int argc, char *argv[] )
963 {
964         return autoca_initialize();
965 }
966 #endif
967
968 #endif /* defined(SLAPD_OVER_AUTOCA) */