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