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