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