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, ×tamp))
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