1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright (c) 1999 by Sun Microsystems, Inc.
24 * All rights reserved.
25 */
26
27 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 /*
30 * This file contains all authentication-related functionality for
31 * SLP. Two interfaces are exported:
32 *
33 * slp_sign: Creates auth blocks for a given piece of data
34 * slp_verify: Verifies an auth block for a given piece of data.
35 *
36 * A shared object which provides crypto-suites and key management
37 * functionality is dynamically linked in during intialization. If
38 * the shared object cannot be found, the authentication code aborts
39 * and an SLP_AUTHENTICATION_FAILED error is returned. Which shared
40 * object is actually loaded is controlled by the property
41 * sun.net.slp.authBackend; the value of this property should contain
42 * either the name of a shared object which implements the necessary
43 * interfaces, or a full or relative path to such an object. This value
44 * will be passed to dlopen(3X) to resolve the symbols.
45 *
46 * The shared object must implement the following AMI interfaces:
47 *
48 * ami_init
49 * ami_sign
50 * ami_verify
51 * ami_get_cert
52 * ami_get_cert_chain
53 * ami_strerror
54 * ami_end
55 * AMI_MD5WithRSAEncryption_AID
56 * AMI_SHA1WithDSASignature_AID
57 *
58 * See security/ami.h for more info on these interfaces.
59 */
60
61 #include <stdio.h>
62 #include <string.h>
63 #include <stdlib.h>
64 #include <syslog.h>
65 #include <synch.h>
66 #include <dlfcn.h>
67 #include <slp-internal.h>
68 #include "slp_ami.h"
69
70 /* Prototypes for dynamically loaded (dl'd) AMI functions */
71 static ami_algid **ami_rsa_aid, **ami_dsa_aid;
72 static AMI_STATUS (*dld_ami_init)(ami_handle_t **, const char *,
73 const char *, const u_int, const u_int,
74 const char *);
75
76 static AMI_STATUS (*dld_ami_sign)(ami_handle_t *,
77 const uchar_t *,
78 const size_t,
79 const int,
80 const ami_algid *,
81 const uchar_t *,
82 const size_t,
83 const ami_algid *,
84 uchar_t **,
85 size_t *);
86 static AMI_STATUS (*dld_ami_verify)(ami_handle_t *,
87 const uchar_t *,
88 const size_t,
89 const int,
90 const ami_algid *,
91 const uchar_t *,
92 const size_t,
93 const ami_algid *,
94 const uchar_t *,
95 const size_t);
96 static AMI_STATUS (*dld_ami_get_cert)(const ami_handle_t *,
97 const char *,
98 ami_cert **,
99 int *);
100 static AMI_STATUS (*dld_ami_get_cert_chain)(const ami_handle_t *,
101 const ami_cert *,
102 const char **,
103 int flags,
104 ami_cert **,
105 int *);
106 static AMI_STATUS (*dld_ami_str2dn)(const ami_handle_t *,
107 char *, ami_name **);
108 static AMI_STATUS (*dld_ami_dn2str)(const ami_handle_t *,
109 ami_name *, char **);
110 static void (*dld_ami_free_cert_list)(ami_cert **, int);
111 static void (*dld_ami_free_dn)(ami_name **);
112 static char *(*dld_ami_strerror)(const ami_handle_t *, const AMI_STATUS);
113 static AMI_STATUS (*dld_ami_end)(ami_handle_t *);
114
115 /* local utilities */
116 static SLPError get_security_backend();
117 static SLPError make_tbs(const char *, struct iovec *, int,
118 unsigned int, unsigned char **, size_t *);
119 static SLPError make_authblock(struct iovec *, int, const char *,
120 time_t, caddr_t *, size_t *);
121 static SLPError do_verify(unsigned char *, size_t, unsigned short,
122 const unsigned char *, size_t, const char *);
123 static char *alias2dn(ami_handle_t *);
124 static SLPError check_spis(ami_handle_t *, ami_cert *, int, const char *);
125 static int dncmp(ami_handle_t *, const char *, const char *);
126
127 /*
128 * Creates a cryptographic signature over the components of authiov, and
129 * creates an auth block from the signature. The auth block is placed
130 * into msgiov at the index specified by msgiov_index. The timestamp
131 * for the auth block is given in ts. Caller must free the auth block
132 * when finished.
133 *
134 * Returns SLP_OK on success, SLP_AUTHENTICATION_FAILED on failure.
135 */
slp_sign(struct iovec * authiov,int authiov_len,time_t ts,struct iovec * msgiov,int msg_index)136 SLPError slp_sign(struct iovec *authiov, int authiov_len, time_t ts,
137 struct iovec *msgiov, int msg_index) {
138
139 char *sign_as = NULL;
140 char *alias, *aliasp;
141 SLPError err = SLP_OK;
142 unsigned char num_auths = 0;
143
144 /* This auth block is always at least 1 byte long, for num auths */
145 msgiov[msg_index].iov_base = calloc(1, 1);
146 msgiov[msg_index].iov_len = 1;
147
148 /* if security is off, just return the empty auth block */
149 if (!slp_get_security_on() || slp_get_bypass_auth()) {
150 return (SLP_OK);
151 }
152
153 /*
154 * Security is disabled in Solaris 8 due to AMI trouble.
155 * The pragmas and LINTED suppress "statement not reached"
156 * compiler and lint warnings, and should be removed when
157 * security is re-enabled.
158 */
159 return (SLP_SECURITY_UNAVAILABLE);
160
161 #pragma error_messages(off, E_STATEMENT_NOT_REACHED)
162
163 /* else we should sign this advert */
164 if (!(sign_as = (char *)SLPGetProperty(SLP_CONFIG_SIGN_AS)) ||
165 /*LINTED statement not reached*/
166 !*sign_as) {
167
168 slp_err(LOG_INFO, 0, "slp_sign", "No signing identity given");
169 return (SLP_AUTHENTICATION_FAILED);
170 }
171
172 /* Try to initialize security backend */
173 if (!(err = get_security_backend()) == SLP_OK) {
174 return (SLP_AUTHENTICATION_FAILED);
175 }
176
177 /* dup SPI list so we can destructively modify it */
178 if (!(sign_as = strdup(sign_as))) {
179 slp_err(LOG_CRIT, 0, "slp_sign", "out of memory");
180 return (SLP_MEMORY_ALLOC_FAILED);
181 }
182
183 /* For each SPI, create an auth block */
184 for (aliasp = sign_as; aliasp; ) {
185 alias = aliasp;
186 aliasp = slp_utf_strchr(aliasp, ',');
187 if (aliasp) {
188 *aliasp++ = 0;
189 }
190
191 /* create an auth block for this SPI */
192 err = make_authblock(authiov, authiov_len, alias, ts,
193 &(msgiov[msg_index].iov_base),
194 (size_t *)&(msgiov[msg_index].iov_len));
195 if (err == SLP_MEMORY_ALLOC_FAILED) {
196 goto done;
197 } else if (err != SLP_OK) {
198 /* else skip and keep going */
199 continue;
200 }
201
202 num_auths++;
203 }
204
205 done:
206 if (sign_as) free(sign_as);
207
208 if (err != SLP_OK) {
209 return (err);
210 }
211
212 if (num_auths == 0) {
213 return (SLP_AUTHENTICATION_FAILED);
214 } else {
215 size_t off = 0;
216 /* Lay in number of auth blocks created */
217 err = slp_add_byte(msgiov[msg_index].iov_base, 1, num_auths, &off);
218 }
219
220 return (err);
221 #pragma error_messages(on, E_STATEMENT_NOT_REACHED)
222 }
223
224 /*
225 * Verifies that the signature(s) contained in authblocks validates
226 * the data in authiov. slp_verify will not read more than len bytes
227 * from authblocks. n is the stated number of authblocks in authblock.
228 * The total length of all auth blocks read is placed in *total.
229 *
230 * Returns SLP_OK if the verification succeeds.
231 */
slp_verify(struct iovec * authiov,int authiov_len,const char * authblocks,size_t len,int n,size_t * total)232 SLPError slp_verify(struct iovec *authiov, int authiov_len,
233 const char *authblocks, size_t len, int n, size_t *total) {
234 int i;
235 size_t off, this_ab;
236 unsigned short bsd, ablen;
237 unsigned int timestamp;
238 char *spi = NULL;
239 SLPError err = SLP_AUTHENTICATION_FAILED;
240 unsigned char *inbytes = NULL;
241 size_t inbytes_len;
242 unsigned char *sig;
243 size_t siglen;
244
245 /* 1st: if bypass_auth == true, just return SLP_OK */
246 if (slp_get_bypass_auth()) {
247 return (SLP_OK);
248 }
249
250 /* 2nd: If security is off, and there are no auth blocks, OK */
251 if (!slp_get_security_on() && n == 0) {
252 return (SLP_OK);
253 }
254
255 /*
256 * Security is disabled in Solaris 8 due to AMI trouble.
257 * The pragmas and LINTED suppress "statement not reached"
258 * compiler and lint warnings, and should be removed when
259 * security is re-enabled.
260 */
261 return (SLP_SECURITY_UNAVAILABLE);
262 #pragma error_messages(off, E_STATEMENT_NOT_REACHED)
263
264 /* For all other scenarios, we must verify the auth blocks */
265 /*LINTED statement not reached*/
266 if (get_security_backend() != SLP_OK || n == 0) {
267 return (SLP_AUTHENTICATION_FAILED);
268 }
269
270 /*
271 * If we get here, the backend is available and there are auth
272 * blocks to verify. Verify each input auth block.
273 */
274 off = 0; /* offset into raw auth blocks */
275
276 for (i = 0; i < n && off <= len; i++) {
277 this_ab = off;
278
279 /* BSD */
280 if ((err = slp_get_sht(authblocks, len, &off, &bsd)) != SLP_OK) {
281 slp_err(LOG_INFO, 0, "slp_verify", "corrupt auth block");
282 goto done;
283 }
284
285 /* Auth block length */
286 if ((err = slp_get_sht(authblocks, len, &off, &ablen)) != SLP_OK) {
287 slp_err(LOG_INFO, 0, "slp_verify", "corrupt auth block");
288 goto done;
289 }
290
291 /* Time stamp */
292 if ((err = slp_get_int32(authblocks, len, &off, ×tamp))
293 != SLP_OK) {
294 slp_err(LOG_INFO, 0, "slp_verify", "corrupt auth block");
295 goto done;
296 }
297
298 /* SPI string */
299 if ((err = slp_get_string(authblocks, len, &off, &spi))
300 != SLP_OK) {
301 slp_err(LOG_INFO, 0, "slp_verify", "corrupt auth block");
302 goto done;
303 }
304
305 err = make_tbs(
306 spi, authiov, authiov_len, timestamp, &inbytes, &inbytes_len);
307 if (err != SLP_OK) {
308 goto done;
309 }
310
311 sig = (unsigned char *)(authblocks + off);
312 siglen = ablen - (off - this_ab);
313
314 off += siglen;
315
316 err = do_verify(inbytes, inbytes_len, bsd, sig, siglen, spi);
317 if (err != SLP_OK) {
318 free(spi);
319 goto done;
320 }
321
322 free(spi);
323 }
324
325 done:
326 if (inbytes) free(inbytes);
327 *total = off;
328
329 return (err);
330 #pragma error_messages(on, E_STATEMENT_NOT_REACHED)
331 }
332
333 /*
334 * When first called, attempts to dlopen a security shared library
335 * and dlsym in the necessary interfaces. The library remains mapped
336 * in, so successive calls just return SLP_OK.
337 */
get_security_backend()338 static SLPError get_security_backend() {
339 static mutex_t be_lock = DEFAULTMUTEX;
340 static void *dl = NULL;
341 static int got_backend = 0;
342 SLPError err = SLP_SECURITY_UNAVAILABLE;
343 const char *libname;
344 char *dlerr;
345
346 (void) mutex_lock(&be_lock);
347
348 if (got_backend) {
349 (void) mutex_unlock(&be_lock);
350 return (SLP_OK);
351 }
352
353 if (!(libname = SLPGetProperty(SLP_CONFIG_AUTH_BACKEND)) ||
354 !*libname) {
355 /* revert to default */
356 libname = "libami.so.1";
357 }
358
359 if (!(dl = dlopen(libname, RTLD_LAZY))) {
360 dlerr = dlerror();
361 slp_err(LOG_INFO, 0, "get_security_backend",
362 "Could not dlopen AMI library: %s",
363 (dlerr ? dlerr : "unknown DL error"));
364 slp_err(LOG_INFO, 0, "get_security_backend",
365 "Is AMI installed?");
366 goto done;
367 }
368
369 /* Relocate AMI's statically initialized AIDs we need */
370 if (!(ami_rsa_aid =
371 dlsym(dl, "AMI_MD5WithRSAEncryption_AID"))) {
372
373 dlerr = dlerror();
374 slp_err(LOG_INFO, 0, "get_security_backend",
375 "Could not relocate AMI_MD5WithRSAEncryption_AID: %s",
376 (dlerr ? dlerr : "unknown DL error"));
377 goto done;
378 }
379
380 if (!(ami_dsa_aid =
381 dlsym(dl, "AMI_SHA1WithDSASignature_AID"))) {
382
383 dlerr = dlerror();
384 slp_err(LOG_INFO, 0, "get_security_backend",
385 "Could not relocate AMI_SHA1WithDSASignature_AID: %s",
386 (dlerr ? dlerr : "unknown DL error"));
387 goto done;
388 }
389
390 /* Bring in the functions we need */
391 if (!(dld_ami_init = (AMI_STATUS (*)(ami_handle_t **,
392 const char *,
393 const char *,
394 const u_int,
395 const u_int,
396 const char *))dlsym(
397 dl, "ami_init"))) {
398 slp_err(LOG_INFO, 0, "get_security_backend",
399 "Could not load ami_init");
400 goto done;
401 }
402
403 if (!(dld_ami_sign = (AMI_STATUS (*)(ami_handle_t *,
404 const uchar_t *,
405 const size_t,
406 const int,
407 const ami_algid *,
408 const uchar_t *,
409 const size_t,
410 const ami_algid *,
411 uchar_t **,
412 size_t *))dlsym(
413 dl, "ami_sign"))) {
414 slp_err(LOG_INFO, 0, "get_security_backend",
415 "Could not load ami_sign");
416 goto done;
417 }
418
419 if (!(dld_ami_verify = (AMI_STATUS (*)(ami_handle_t *,
420 const uchar_t *,
421 const size_t,
422 const int,
423 const ami_algid *,
424 const uchar_t *,
425 const size_t,
426 const ami_algid *,
427 const uchar_t *,
428 const size_t))dlsym(
429 dl, "ami_verify"))) {
430 slp_err(LOG_INFO, 0, "get_security_backend",
431 "Could not load ami_verify");
432 goto done;
433 }
434
435 if (!(dld_ami_get_cert = (AMI_STATUS (*)(const ami_handle_t *,
436 const char *,
437 ami_cert **,
438 int *))dlsym(
439 dl, "ami_get_cert"))) {
440 slp_err(LOG_INFO, 0, "get_security_backend",
441 "Could not load ami_get_cert");
442 goto done;
443 }
444
445 if (!(dld_ami_get_cert_chain = (AMI_STATUS (*)(const ami_handle_t *,
446 const ami_cert *,
447 const char **,
448 int flags,
449 ami_cert **,
450 int *))dlsym(
451 dl, "ami_get_cert_chain"))) {
452 slp_err(LOG_INFO, 0, "get_security_backend",
453 "Could not load ami_get_cert_chain");
454 goto done;
455 }
456
457 if (!(dld_ami_str2dn = (AMI_STATUS (*)(const ami_handle_t *,
458 char *, ami_name **))dlsym(
459 dl, "ami_str2dn"))) {
460 slp_err(LOG_INFO, 0, "get_security_backend",
461 "Could not load ami_str2dn");
462 goto done;
463 }
464
465 if (!(dld_ami_dn2str = (AMI_STATUS (*)(const ami_handle_t *,
466 ami_name *, char **))dlsym(
467 dl, "ami_dn2str"))) {
468 slp_err(LOG_INFO, 0, "get_security_backend",
469 "Could not load ami_dn2str");
470 goto done;
471 }
472
473 if (!(dld_ami_free_cert_list = (void (*)(ami_cert **, int))dlsym(
474 dl, "ami_free_cert_list"))) {
475 slp_err(LOG_INFO, 0, "get_security_backend",
476 "Could not load ami_free_cert_list");
477 goto done;
478 }
479
480 if (!(dld_ami_free_dn = (void (*)(ami_name **))dlsym(
481 dl, "ami_free_dn"))) {
482 slp_err(LOG_INFO, 0, "get_security_backend",
483 "Could not load ami_free_dn");
484 goto done;
485 }
486
487 if (!(dld_ami_strerror = (char *(*)(const ami_handle_t *,
488 const AMI_STATUS))dlsym(
489 dl, "ami_strerror"))) {
490 slp_err(LOG_INFO, 0, "get_security_backend",
491 "Could not load ami_strerror");
492 goto done;
493 }
494
495 if (!(dld_ami_end = (AMI_STATUS (*)(ami_handle_t *))dlsym(
496 dl, "ami_end"))) {
497
498 slp_err(LOG_INFO, 0, "get_security_backend",
499 "Could not load ami_end");
500 goto done;
501 }
502
503 got_backend = 1;
504 err = SLP_OK;
505
506 done:
507 if (!got_backend && dl) {
508 (void) dlclose(dl);
509 }
510 (void) mutex_unlock(&be_lock);
511
512 return (err);
513 }
514
515 /*
516 * Creates a bytes to-be-signed buffer suitable for input
517 * a signature algorithm.
518 *
519 * The only backend currently available is AMI, which does
520 * not support incremental updates for digesting. Hence we
521 * must copy all elements of the input iovec into one buffer.
522 *
523 * This function allocates a single buffer into *buf big enough
524 * to hold all necessary elements, sets *buflen to this length, and
525 * makes a bytes-to-be-signed buffer. Into this buffer is placed
526 * first the SPI string, then all elements of iov, and finally
527 * the timestamp. Caller must free *buf.
528 *
529 * Returns err != SLP_OK only on catastrophic error.
530 */
make_tbs(const char * spi,struct iovec * iov,int iovlen,unsigned int timestamp,unsigned char ** buf,size_t * buflen)531 static SLPError make_tbs(const char *spi,
532 struct iovec *iov,
533 int iovlen,
534 unsigned int timestamp,
535 unsigned char **buf,
536 size_t *buflen) {
537 int i;
538 caddr_t p;
539 size_t off;
540 SLPError err;
541
542 *buflen = 2 + strlen(spi);
543
544 for (i = 0; i < iovlen; i++) {
545 *buflen += iov[i].iov_len;
546 }
547
548 *buflen += sizeof (timestamp);
549
550 if (!(*buf = malloc(*buflen))) {
551 slp_err(LOG_CRIT, 0, "slp_sign", "out of memory");
552 return (SLP_MEMORY_ALLOC_FAILED);
553 }
554
555 /* @@@ ok to use caddr_t? */
556 p = (caddr_t)*buf;
557
558 /* Lay in SPI string */
559 off = 0;
560 if ((err = slp_add_string(p, *buflen, spi, &off)) != SLP_OK) {
561 return (err);
562 }
563
564 p += off;
565
566 /* Copy in elements of iov */
567 for (i = 0; i < iovlen; i++) {
568 (void) memcpy(p, iov[i].iov_base, iov[i].iov_len);
569 p += iov[i].iov_len;
570 off += iov[i].iov_len;
571 }
572
573 /* Lay in timestamp */
574 return (slp_add_int32((char *)*buf, *buflen, timestamp, &off));
575 }
576
577 /*
578 * Creates an auth block from the given parameters:
579 *
580 * sig_in IN Data to be signed
581 * sig_in_len IN Length of sig_in
582 * alias IN signing alias for this auth block
583 * timestamp IN Timestamp for this auth block
584 * abs IN/OUT Buffer of accumulated auth blocks
585 * abs_len IN/OUT Length of abs
586 *
587 * For each new auth block, abs is resized as necessary, and the
588 * new auth block is appended. abs_len is updated accordingly.
589 *
590 * Returns SLP_OK if the signing and auth block creation succeeded.
591 */
make_authblock(struct iovec * authiov,int authiov_len,const char * alias,time_t timestamp,caddr_t * abs,size_t * abs_len)592 static SLPError make_authblock(struct iovec *authiov, int authiov_len,
593 const char *alias, time_t timestamp,
594 caddr_t *abs, size_t *abs_len) {
595
596 unsigned char *sig_out = NULL;
597 size_t sig_out_len = 0;
598 ami_handle_t *amih = NULL;
599 AMI_STATUS ami_err;
600 size_t off = 0;
601 SLPError err = SLP_OK;
602 caddr_t ab;
603 size_t ab_len;
604 unsigned short bsd;
605 ami_algid *aid;
606 char *dn = NULL;
607 unsigned char *sig_in = NULL;
608 size_t sig_in_len;
609
610 /* Create the signature */
611 if ((ami_err = dld_ami_init(&amih, alias, NULL, 0, 0, NULL))
612 != AMI_OK) {
613 slp_err(LOG_INFO, 0, "make_authblock", "ami_init failed: %s",
614 dld_ami_strerror(amih, ami_err));
615 return (SLP_AUTHENTICATION_FAILED);
616 }
617
618 /* determine our DN, to be used as the SPI */
619 if (!(dn = alias2dn(amih))) {
620 err = SLP_AUTHENTICATION_FAILED;
621 goto done;
622 }
623
624 /* make bytes to-be-signed */
625 err = make_tbs(
626 dn, authiov, authiov_len, timestamp, &sig_in, &sig_in_len);
627 if (err != SLP_OK) {
628 goto done;
629 }
630
631 /* @@@ determine the AID and BSD for this alias */
632 bsd = 1;
633 aid = *ami_rsa_aid;
634
635 if ((ami_err = dld_ami_sign(amih, sig_in, sig_in_len, AMI_END_DATA,
636 NULL, NULL, 0, aid, &sig_out, &sig_out_len))
637 != AMI_OK) {
638
639 slp_err(LOG_INFO, 0, "make_authblock", "ami_sign failed: %s",
640 dld_ami_strerror(amih, ami_err));
641 err = SLP_AUTHENTICATION_FAILED;
642 goto done;
643 }
644
645 /* We can now calculate the length of the auth block */
646 ab_len =
647 2 + /* BSD */
648 2 + /* length */
649 4 + /* timestamp */
650 2 + strlen(dn) + /* SPI string */
651 sig_out_len; /* the signature */
652
653 /* Grow buffer for already-created auth blocks, if necessary */
654 if (*abs_len != 0) {
655 if (!(*abs = realloc(*abs, *abs_len + ab_len))) {
656 slp_err(LOG_CRIT, 0, "make_authblock", "out of memory");
657 err = SLP_MEMORY_ALLOC_FAILED;
658 goto done;
659 }
660 }
661 ab = *abs + *abs_len;
662 *abs_len += ab_len;
663
664 /* BSD */
665 err = slp_add_sht(ab, ab_len, bsd, &off);
666
667 /* Auth block length */
668 if (err == SLP_OK) {
669 err = slp_add_sht(ab, ab_len, ab_len, &off);
670 }
671
672 /* timestamp */
673 if (err == SLP_OK) {
674 err = slp_add_int32(ab, ab_len, timestamp, &off);
675 }
676
677 /* SPI string */
678 if (err == SLP_OK) {
679 err = slp_add_string(ab, ab_len, dn, &off);
680 }
681
682 /* Signature */
683 if (err == SLP_OK) {
684 (void) memcpy(ab + off, sig_out, sig_out_len);
685 }
686
687 done:
688 if (amih) {
689 dld_ami_end(amih);
690 }
691 if (dn) free(dn);
692
693 if (sig_in) free(sig_in);
694 if (sig_out) free(sig_out);
695
696 if (err == SLP_MEMORY_ALLOC_FAILED) {
697 /* critical error; abort */
698 free(*abs);
699 }
700
701 return (err);
702 }
703
704 /*
705 * The actual verification routine which interacts with the security
706 * backend to get a certificate for the given SPI and use that cert
707 * to verify the signature contained in the auth block.
708 *
709 * inbytes IN bytes to be verified
710 * inbytes_len IN length of inbytes
711 * bsd IN BSD for this signature
712 * sig IN the signature
713 * siglen IN length of sig
714 * spi IN SPI for this signature, not escaped
715 *
716 * Returns SLP_OK if the signature is verified, or SLP_AUTHENTICATION_FAILED
717 * if any error occured.
718 */
do_verify(unsigned char * inbytes,size_t inbytes_len,unsigned short bsd,const unsigned char * sig,size_t siglen,const char * esc_spi)719 static SLPError do_verify(unsigned char *inbytes, size_t inbytes_len,
720 unsigned short bsd, const unsigned char *sig,
721 size_t siglen, const char *esc_spi) {
722
723 AMI_STATUS ami_err;
724 ami_handle_t *amih = NULL;
725 SLPError err;
726 ami_cert *certs = NULL;
727 int icert, ccnt;
728 ami_algid *aid;
729 char *spi = NULL;
730
731 /* Get the right AID */
732 switch (bsd) {
733 case 1:
734 aid = *ami_rsa_aid;
735 break;
736 case 2:
737 aid = *ami_dsa_aid;
738 break;
739 default:
740 slp_err(LOG_INFO, 0, "do_verify",
741 "Unsupported BSD %d for given SPI %s", bsd, spi);
742 return (SLP_AUTHENTICATION_FAILED);
743 }
744
745 if ((ami_err = dld_ami_init(&amih, spi, NULL, 0, 0, NULL)) != AMI_OK) {
746 slp_err(LOG_INFO, 0, "do_verify", "ami_init failed: %s",
747 dld_ami_strerror(amih, ami_err));
748 return (SLP_AUTHENTICATION_FAILED);
749 }
750
751 /* unescape SPI */
752 if ((err = SLPUnescape(esc_spi, &spi, SLP_FALSE))) {
753 goto done;
754 }
755
756 /* get certificate */
757 if ((ami_err = dld_ami_get_cert(amih, spi, &certs, &ccnt)) != AMI_OK) {
758 slp_err(LOG_INFO, 0, "do_verify",
759 "Can not get certificate for %s: %s",
760 spi, dld_ami_strerror(amih, ami_err));
761 err = SLP_AUTHENTICATION_FAILED;
762 goto done;
763 }
764
765 /* @@@ select the right cert, if more than one */
766 icert = 0;
767
768 if ((ami_err = dld_ami_verify(amih, inbytes, inbytes_len, AMI_END_DATA,
769 certs[icert].info.pubKeyInfo->algorithm,
770 certs[icert].info.pubKeyInfo->pubKey.value,
771 certs[icert].info.pubKeyInfo->pubKey.length,
772 aid, sig, siglen)) != AMI_OK) {
773
774 slp_err(LOG_INFO, 0, "do_verify", "ami_verify failed: %s",
775 dld_ami_strerror(amih, ami_err));
776 err = SLP_AUTHENTICATION_FAILED;
777 goto done;
778 }
779
780 err = check_spis(amih, certs, icert, spi);
781
782 done:
783 if (certs) {
784 dld_ami_free_cert_list(&certs, ccnt);
785 }
786
787 if (amih) {
788 dld_ami_end(amih);
789 }
790
791 if (spi) free(spi);
792
793 return (err);
794 }
795
796 /*
797 * Gets this process' DN, or returns NULL on failure. Caller must free
798 * the result. The reslting DN will be escaped.
799 */
alias2dn(ami_handle_t * amih)800 static char *alias2dn(ami_handle_t *amih) {
801 ami_cert *certs;
802 int ccnt;
803 AMI_STATUS status;
804 char *answer = NULL;
805 char *esc_answer;
806
807 if ((status = dld_ami_get_cert(amih, NULL, &certs, &ccnt)) != AMI_OK) {
808 slp_err(LOG_INFO, 0, "alias2dn",
809 "Can not get my DN: %s",
810 dld_ami_strerror(amih, status));
811 return (NULL);
812 }
813
814 if (ccnt == 0) {
815 slp_err(LOG_INFO, 0, "alias2dn",
816 "No cert found for myself");
817 return (NULL);
818 }
819
820 if ((status = dld_ami_dn2str(amih, certs[0].info.subject, &answer))
821 != AMI_OK) {
822 slp_err(LOG_INFO, 0, "alias2dn",
823 "Can not convert DN to string: %s",
824 dld_ami_strerror(amih, status));
825 answer = NULL;
826 goto done;
827 }
828
829 if (SLPEscape(answer, &esc_answer, SLP_FALSE) != SLP_OK) {
830 free(answer);
831 answer = NULL;
832 } else {
833 free(answer);
834 answer = esc_answer;
835 }
836
837 done:
838 dld_ami_free_cert_list(&certs, ccnt);
839
840 return (answer);
841 }
842
check_spis(ami_handle_t * amih,ami_cert * certs,int icert,const char * spi)843 static SLPError check_spis(ami_handle_t *amih,
844 ami_cert *certs,
845 int icert,
846 const char *spi) {
847 ami_cert *chain = NULL;
848 int ccnt;
849 const char *cas[2];
850 char *prop_spi;
851 char *ue_spi;
852 char *p;
853 SLPError err;
854 AMI_STATUS ami_err;
855
856 /* If configured SPI == authblock SPI, we are done */
857 prop_spi = (char *)SLPGetProperty(SLP_CONFIG_SPI);
858 if (!prop_spi || !*prop_spi) {
859 slp_err(LOG_INFO, 0, "do_verify", "no SPI configured");
860 err = SLP_AUTHENTICATION_FAILED;
861 goto done;
862 }
863
864 /* dup it so we can modify it */
865 if (!(prop_spi = strdup(prop_spi))) {
866 slp_err(LOG_CRIT, 0, "do_verify", "out of memory");
867 err = SLP_MEMORY_ALLOC_FAILED;
868 goto done;
869 }
870
871 /* if more than one SPI given, discard all but first */
872 if ((p = slp_utf_strchr(prop_spi, ','))) {
873 *p = 0;
874 }
875
876 /* unescape configured DNs */
877 if ((err = SLPUnescape(prop_spi, &ue_spi, SLP_FALSE)) != SLP_OK) {
878 goto done;
879 }
880 free(prop_spi);
881 prop_spi = ue_spi;
882
883 if (dncmp(amih, prop_spi, spi) == 0) {
884 /* they match, so we are done */
885 err = SLP_OK;
886 goto done;
887 }
888
889 /*
890 * Else we need to traverse the cert chain. ami_get_cert_chain
891 * verifies each link in the chain, so no need to do it again.
892 */
893 cas[0] = prop_spi;
894 cas[1] = NULL;
895 ami_err = dld_ami_get_cert_chain(amih, certs + icert, cas, 0,
896 &chain, &ccnt);
897 if (ami_err != AMI_OK) {
898 slp_err(LOG_INFO, 0, "do_verify",
899 "can not get cert chain: %s",
900 dld_ami_strerror(amih, ami_err));
901 err = SLP_AUTHENTICATION_FAILED;
902 goto done;
903 }
904
905 err = SLP_OK;
906
907 done:
908 if (chain) {
909 dld_ami_free_cert_list(&chain, ccnt);
910 }
911
912 if (prop_spi) free(prop_spi);
913
914 return (err);
915 }
916
dncmp(ami_handle_t * amih,const char * s1,const char * s2)917 static int dncmp(ami_handle_t *amih, const char *s1, const char *s2) {
918 AMI_STATUS status;
919 ami_name *dn1 = NULL;
920 ami_name *dn2 = NULL;
921 char *dnstr1 = NULL;
922 char *dnstr2 = NULL;
923 int answer;
924
925 /* Normalize: convert to DN structs and back to strings */
926 if ((status = dld_ami_str2dn(amih, (char *)s1, &dn1)) != AMI_OK) {
927 slp_err(LOG_INFO, 0, "dncmp",
928 "can not create DN structure for %s: %s",
929 s1,
930 dld_ami_strerror(amih, status));
931 answer = 1;
932 goto done;
933 }
934
935 if ((status = dld_ami_str2dn(amih, (char *)s2, &dn2)) != AMI_OK) {
936 slp_err(LOG_INFO, 0, "dncmp",
937 "can not create DN structure for %s: %s",
938 s2,
939 dld_ami_strerror(amih, status));
940 answer = 1;
941 goto done;
942 }
943
944 /* convert back to strings */
945 if ((status = dld_ami_dn2str(amih, dn1, &dnstr1)) != AMI_OK) {
946 slp_err(LOG_INFO, 0, "dncmp",
947 "can not convert DN to string: %s",
948 dld_ami_strerror(amih, status));
949 answer = 1;
950 goto done;
951 }
952
953 if ((status = dld_ami_dn2str(amih, dn2, &dnstr2)) != AMI_OK) {
954 slp_err(LOG_INFO, 0, "dncmp",
955 "can not convert DN to string: %s",
956 dld_ami_strerror(amih, status));
957 answer = 1;
958 goto done;
959 }
960
961 answer = strcasecmp(dnstr1, dnstr2);
962
963 done:
964 if (dn1) {
965 dld_ami_free_dn(&dn1);
966 }
967
968 if (dn2) {
969 dld_ami_free_dn(&dn2);
970 }
971
972 if (dnstr1) free(dnstr1);
973 if (dnstr2) free(dnstr2);
974
975 return (answer);
976 }
977