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