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