1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2002-2003 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  *	This provides the interface to store a named key in stable local
31  *	storage.  These keys are retrieved and used by OBP and WAN boot
32  *	to do decryption and HMAC verification of network-downloaded data.
33  */
34 
35 #include <sys/promimpl.h>
36 #ifdef	PROM_32BIT_ADDRS
37 #include <sys/sunddi.h>
38 #endif	/* PROM_32BIT_ADDRS */
39 
40 int
prom_set_security_key(char * keyname,caddr_t buf,int buflen,int * reslen,int * status)41 prom_set_security_key(char *keyname, caddr_t buf, int buflen, int *reslen,
42     int *status)
43 {
44 	int	rv;
45 	cell_t	ci[7];
46 	int	result;
47 #ifdef	PROM_32BIT_ADDRS
48 	char	*okeyname = NULL;
49 	char	*obuf = NULL;
50 	size_t	keynamelen;
51 
52 	if ((uintptr_t)keyname > (uint32_t)-1) {
53 		okeyname = keyname;
54 		keynamelen = prom_strlen(okeyname) + 1;	/* include '\0' */
55 		keyname = promplat_alloc(keynamelen);
56 		if (keyname == NULL)
57 			return (-1);
58 		(void) prom_strcpy(keyname, okeyname);
59 	}
60 
61 	/*
62 	 *	A key length of zero is used to delete the named key.
63 	 *	No need to reallocate and copy buf[] in this case.
64 	 */
65 	if (buflen > 0 && ((uintptr_t)buf > (uint32_t)-1)) {
66 		obuf = buf;
67 		buf = promplat_alloc(buflen);
68 		if ((buf == NULL) && (okeyname != NULL)) {
69 			promplat_free(keyname, keynamelen);
70 			return (-1);
71 		}
72 		promplat_bcopy(obuf, buf, buflen);
73 	}
74 #endif	/* PROM_32BIT_ADDRS */
75 
76 	/*
77 	 *	The arguments to the SUNW,set-security-key service
78 	 *	that stores a key are
79 	 *		ci[0]	the service name
80 	 *		ci[1]	the number of ``in'' arguments
81 	 *		ci[2]	the number of ``out'' arguments
82 	 *		ci[3]	the key's name, as a string
83 	 *		ci[4]	the key buffer itself
84 	 *		ci[5]	the length of the key buffer
85 	 *
86 	 *	When p1275_cif_handler() returns, the return value is
87 	 *		ci[6]	the length of the key stored, or (if
88 	 *			negative) an error code.
89 	 */
90 	ci[0] = p1275_ptr2cell("SUNW,set-security-key");
91 	ci[1] = 3;
92 	ci[2] = 1;
93 	ci[3] = p1275_ptr2cell(keyname);
94 	ci[4] = p1275_ptr2cell(buf);
95 	ci[5] = p1275_uint2cell(buflen);
96 
97 	promif_preprom();
98 	rv = p1275_cif_handler(ci);
99 	promif_postprom();
100 
101 #ifdef	PROM_32BIT_ADDRS
102 	if (okeyname != NULL)
103 		promplat_free(keyname, keynamelen);
104 	if (obuf != NULL)
105 		promplat_free(buf, buflen);
106 #endif	/* PROM_32BIT_ADDRS */
107 
108 	if (rv != 0)
109 		return (-1);
110 
111 	result = p1275_cell2int(ci[6]);
112 	if (result >= 0) {
113 		*reslen = result;
114 		*status = 0;
115 	} else {
116 		*reslen = 0;
117 		*status = result;
118 	}
119 	return (0);
120 }
121 
122 int
prom_get_security_key(char * keyname,caddr_t buf,int buflen,int * keylen,int * status)123 prom_get_security_key(char *keyname, caddr_t buf, int buflen, int *keylen,
124     int *status)
125 {
126 	int	rv;
127 	cell_t	ci[7];
128 	int	result;
129 #ifdef	PROM_32BIT_ADDRS
130 	char	*okeyname = NULL;
131 	char	*obuf = NULL;
132 	size_t	keynamelen;
133 
134 	if ((uintptr_t)keyname > (uint32_t)-1) {
135 		okeyname = keyname;
136 		keynamelen = prom_strlen(okeyname) + 1; /* include '\0' */
137 		keyname = promplat_alloc(keynamelen);
138 		if (keyname == NULL)
139 			return (-1);
140 		(void) prom_strcpy(keyname, okeyname);
141 	}
142 	if ((uintptr_t)buf > (uint32_t)-1) {
143 		obuf = buf;
144 		buf = promplat_alloc(buflen);
145 		if ((buf == NULL) && (okeyname != NULL)) {
146 			promplat_free(keyname, keynamelen);
147 			return (-1);
148 		}
149 	}
150 #endif	/* PROM_32BIT_ADDRS */
151 
152 	/*
153 	 *	The arguments to the SUNW,get-security-key service
154 	 *	that stores a key are
155 	 *		ci[0]	the service name
156 	 *		ci[1]	the number of ``in'' arguments
157 	 *		ci[2]	the number of ``out'' arguments
158 	 *		ci[3]	the key's name, as a string
159 	 *		ci[4]	the key buffer itself
160 	 *		ci[5]	the length of the key buffer
161 	 *
162 	 *	When p1275_cif_handler() returns, the return value is
163 	 *		ci[6]	the length of the key, or (if
164 	 *			negative) an error code.
165 	 */
166 	ci[0] = p1275_ptr2cell("SUNW,get-security-key");
167 	ci[1] = 3;
168 	ci[2] = 1;
169 	ci[3] = p1275_ptr2cell(keyname);
170 	ci[4] = p1275_ptr2cell(buf);
171 	ci[5] = p1275_uint2cell(buflen);
172 
173 	promif_preprom();
174 	rv = p1275_cif_handler(ci);
175 	promif_postprom();
176 
177 #ifdef	PROM_32BIT_ADDRS
178 	if (okeyname != NULL)
179 		promplat_free(keyname, keynamelen);
180 	if (obuf != NULL) {
181 		promplat_bcopy(buf, obuf, buflen);
182 		promplat_free(buf, buflen);
183 	}
184 #endif	/* PROM_32BIT_ADDRS */
185 
186 	if (rv != 0)
187 		return (-1);
188 
189 	result = p1275_cell2int(ci[6]);
190 	if (result > 0) {
191 		*keylen = result;
192 		*status = 0;
193 	} else {
194 		*keylen = 0;
195 		*status = result;
196 	}
197 	return (0);
198 }
199