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