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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 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 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