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