xref: /freebsd/crypto/heimdal/lib/hx509/req.c (revision 2f6a179eb910129fb812c1ad1bdc300da1203dc0)
1 /*
2  * Copyright (c) 2006 Kungliga Tekniska H�gskolan
3  * (Royal Institute of Technology, Stockholm, Sweden).
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * 3. Neither the name of the Institute nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 #include "hx_locl.h"
35 #include <pkcs10_asn1.h>
36 RCSID("$Id: req.c 21344 2007-06-26 14:22:34Z lha $");
37 
38 struct hx509_request_data {
39     hx509_name name;
40     SubjectPublicKeyInfo key;
41     ExtKeyUsage eku;
42     GeneralNames san;
43 };
44 
45 /*
46  *
47  */
48 
49 int
50 _hx509_request_init(hx509_context context, hx509_request *req)
51 {
52     *req = calloc(1, sizeof(**req));
53     if (*req == NULL)
54 	return ENOMEM;
55 
56     return 0;
57 }
58 
59 void
60 _hx509_request_free(hx509_request *req)
61 {
62     if ((*req)->name)
63 	hx509_name_free(&(*req)->name);
64     free_SubjectPublicKeyInfo(&(*req)->key);
65     free_ExtKeyUsage(&(*req)->eku);
66     free_GeneralNames(&(*req)->san);
67     memset(*req, 0, sizeof(**req));
68     free(*req);
69     *req = NULL;
70 }
71 
72 int
73 _hx509_request_set_name(hx509_context context,
74 			hx509_request req,
75 			hx509_name name)
76 {
77     if (req->name)
78 	hx509_name_free(&req->name);
79     if (name) {
80 	int ret = hx509_name_copy(context, name, &req->name);
81 	if (ret)
82 	    return ret;
83     }
84     return 0;
85 }
86 
87 int
88 _hx509_request_get_name(hx509_context context,
89 			hx509_request req,
90 			hx509_name *name)
91 {
92     if (req->name == NULL) {
93 	hx509_set_error_string(context, 0, EINVAL, "Request have no name");
94 	return EINVAL;
95     }
96     return hx509_name_copy(context, req->name, name);
97 }
98 
99 int
100 _hx509_request_set_SubjectPublicKeyInfo(hx509_context context,
101 					hx509_request req,
102 					const SubjectPublicKeyInfo *key)
103 {
104     free_SubjectPublicKeyInfo(&req->key);
105     return copy_SubjectPublicKeyInfo(key, &req->key);
106 }
107 
108 int
109 _hx509_request_get_SubjectPublicKeyInfo(hx509_context context,
110 					hx509_request req,
111 					SubjectPublicKeyInfo *key)
112 {
113     return copy_SubjectPublicKeyInfo(&req->key, key);
114 }
115 
116 int
117 _hx509_request_add_eku(hx509_context context,
118 		       hx509_request req,
119 		       const heim_oid *oid)
120 {
121     void *val;
122     int ret;
123 
124     val = realloc(req->eku.val, sizeof(req->eku.val[0]) * (req->eku.len + 1));
125     if (val == NULL)
126 	return ENOMEM;
127     req->eku.val = val;
128 
129     ret = der_copy_oid(oid, &req->eku.val[req->eku.len]);
130     if (ret)
131 	return ret;
132 
133     req->eku.len += 1;
134 
135     return 0;
136 }
137 
138 int
139 _hx509_request_add_dns_name(hx509_context context,
140 			    hx509_request req,
141 			    const char *hostname)
142 {
143     GeneralName name;
144 
145     memset(&name, 0, sizeof(name));
146     name.element = choice_GeneralName_dNSName;
147     name.u.dNSName = rk_UNCONST(hostname);
148 
149     return add_GeneralNames(&req->san, &name);
150 }
151 
152 int
153 _hx509_request_add_email(hx509_context context,
154 			 hx509_request req,
155 			 const char *email)
156 {
157     GeneralName name;
158 
159     memset(&name, 0, sizeof(name));
160     name.element = choice_GeneralName_rfc822Name;
161     name.u.dNSName = rk_UNCONST(email);
162 
163     return add_GeneralNames(&req->san, &name);
164 }
165 
166 
167 
168 int
169 _hx509_request_to_pkcs10(hx509_context context,
170 			 const hx509_request req,
171 			 const hx509_private_key signer,
172 			 heim_octet_string *request)
173 {
174     CertificationRequest r;
175     heim_octet_string data, os;
176     int ret;
177     size_t size;
178 
179     if (req->name == NULL) {
180 	hx509_set_error_string(context, 0, EINVAL,
181 			       "PKCS10 needs to have a subject");
182 	return EINVAL;
183     }
184 
185     memset(&r, 0, sizeof(r));
186     memset(request, 0, sizeof(*request));
187 
188     r.certificationRequestInfo.version = pkcs10_v1;
189 
190     ret = copy_Name(&req->name->der_name,
191 		    &r.certificationRequestInfo.subject);
192     if (ret)
193 	goto out;
194     ret = copy_SubjectPublicKeyInfo(&req->key,
195 				    &r.certificationRequestInfo.subjectPKInfo);
196     if (ret)
197 	goto out;
198     r.certificationRequestInfo.attributes =
199 	calloc(1, sizeof(*r.certificationRequestInfo.attributes));
200     if (r.certificationRequestInfo.attributes == NULL) {
201 	ret = ENOMEM;
202 	goto out;
203     }
204 
205     ASN1_MALLOC_ENCODE(CertificationRequestInfo, data.data, data.length,
206 		       &r.certificationRequestInfo, &size, ret);
207     if (ret)
208 	goto out;
209     if (data.length != size)
210 	abort();
211 
212     ret = _hx509_create_signature(context,
213 				  signer,
214 				  _hx509_crypto_default_sig_alg,
215 				  &data,
216 				  &r.signatureAlgorithm,
217 				  &os);
218     free(data.data);
219     if (ret)
220 	goto out;
221     r.signature.data = os.data;
222     r.signature.length = os.length * 8;
223 
224     ASN1_MALLOC_ENCODE(CertificationRequest, data.data, data.length,
225 		       &r, &size, ret);
226     if (ret)
227 	goto out;
228     if (data.length != size)
229 	abort();
230 
231     *request = data;
232 
233 out:
234     free_CertificationRequest(&r);
235 
236     return ret;
237 }
238 
239 int
240 _hx509_request_parse(hx509_context context,
241 		     const char *path,
242 		     hx509_request *req)
243 {
244     CertificationRequest r;
245     CertificationRequestInfo *rinfo;
246     hx509_name subject;
247     size_t len, size;
248     void *p;
249     int ret;
250 
251     if (strncmp(path, "PKCS10:", 7) != 0) {
252 	hx509_set_error_string(context, 0, HX509_UNSUPPORTED_OPERATION,
253 			       "unsupport type in %s", path);
254 	return HX509_UNSUPPORTED_OPERATION;
255     }
256     path += 7;
257 
258     /* XXX PEM request */
259 
260     ret = _hx509_map_file(path, &p, &len, NULL);
261     if (ret) {
262 	hx509_set_error_string(context, 0, ret, "Failed to map file %s", path);
263 	return ret;
264     }
265 
266     ret = decode_CertificationRequest(p, len, &r, &size);
267     _hx509_unmap_file(p, len);
268     if (ret) {
269 	hx509_set_error_string(context, 0, ret, "Failed to decode %s", path);
270 	return ret;
271     }
272 
273     ret = _hx509_request_init(context, req);
274     if (ret) {
275 	free_CertificationRequest(&r);
276 	return ret;
277     }
278 
279     rinfo = &r.certificationRequestInfo;
280 
281     ret = _hx509_request_set_SubjectPublicKeyInfo(context, *req,
282 						  &rinfo->subjectPKInfo);
283     if (ret) {
284 	free_CertificationRequest(&r);
285 	_hx509_request_free(req);
286 	return ret;
287     }
288 
289     ret = _hx509_name_from_Name(&rinfo->subject, &subject);
290     if (ret) {
291 	free_CertificationRequest(&r);
292 	_hx509_request_free(req);
293 	return ret;
294     }
295     ret = _hx509_request_set_name(context, *req, subject);
296     hx509_name_free(&subject);
297     free_CertificationRequest(&r);
298     if (ret) {
299 	_hx509_request_free(req);
300 	return ret;
301     }
302 
303     return 0;
304 }
305 
306 
307 int
308 _hx509_request_print(hx509_context context, hx509_request req, FILE *f)
309 {
310     int ret;
311 
312     if (req->name) {
313 	char *subject;
314 	ret = hx509_name_to_string(req->name, &subject);
315 	if (ret) {
316 	    hx509_set_error_string(context, 0, ret, "Failed to print name");
317 	    return ret;
318 	}
319         fprintf(f, "name: %s\n", subject);
320 	free(subject);
321     }
322 
323     return 0;
324 }
325 
326