xref: /freebsd/crypto/heimdal/lib/hx509/req.c (revision 62cfcf62f627e5093fb37026a6d8c98e4d2ef04c)
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 
37 struct hx509_request_data {
38     hx509_name name;
39     SubjectPublicKeyInfo key;
40     ExtKeyUsage eku;
41     GeneralNames san;
42 };
43 
44 /*
45  *
46  */
47 
48 int
49 hx509_request_init(hx509_context context, hx509_request *req)
50 {
51     *req = calloc(1, sizeof(**req));
52     if (*req == NULL)
53 	return ENOMEM;
54 
55     return 0;
56 }
57 
58 void
59 hx509_request_free(hx509_request *req)
60 {
61     if ((*req)->name)
62 	hx509_name_free(&(*req)->name);
63     free_SubjectPublicKeyInfo(&(*req)->key);
64     free_ExtKeyUsage(&(*req)->eku);
65     free_GeneralNames(&(*req)->san);
66     memset(*req, 0, sizeof(**req));
67     free(*req);
68     *req = NULL;
69 }
70 
71 int
72 hx509_request_set_name(hx509_context context,
73 			hx509_request req,
74 			hx509_name name)
75 {
76     if (req->name)
77 	hx509_name_free(&req->name);
78     if (name) {
79 	int ret = hx509_name_copy(context, name, &req->name);
80 	if (ret)
81 	    return ret;
82     }
83     return 0;
84 }
85 
86 int
87 hx509_request_get_name(hx509_context context,
88 			hx509_request req,
89 			hx509_name *name)
90 {
91     if (req->name == NULL) {
92 	hx509_set_error_string(context, 0, EINVAL, "Request have no name");
93 	return EINVAL;
94     }
95     return hx509_name_copy(context, req->name, name);
96 }
97 
98 int
99 hx509_request_set_SubjectPublicKeyInfo(hx509_context context,
100 					hx509_request req,
101 					const SubjectPublicKeyInfo *key)
102 {
103     free_SubjectPublicKeyInfo(&req->key);
104     return copy_SubjectPublicKeyInfo(key, &req->key);
105 }
106 
107 int
108 hx509_request_get_SubjectPublicKeyInfo(hx509_context context,
109 					hx509_request req,
110 					SubjectPublicKeyInfo *key)
111 {
112     return copy_SubjectPublicKeyInfo(&req->key, key);
113 }
114 
115 int
116 _hx509_request_add_eku(hx509_context context,
117 		       hx509_request req,
118 		       const heim_oid *oid)
119 {
120     void *val;
121     int ret;
122 
123     val = realloc(req->eku.val, sizeof(req->eku.val[0]) * (req->eku.len + 1));
124     if (val == NULL)
125 	return ENOMEM;
126     req->eku.val = val;
127 
128     ret = der_copy_oid(oid, &req->eku.val[req->eku.len]);
129     if (ret)
130 	return ret;
131 
132     req->eku.len += 1;
133 
134     return 0;
135 }
136 
137 int
138 _hx509_request_add_dns_name(hx509_context context,
139 			    hx509_request req,
140 			    const char *hostname)
141 {
142     GeneralName name;
143 
144     memset(&name, 0, sizeof(name));
145     name.element = choice_GeneralName_dNSName;
146     name.u.dNSName.data = rk_UNCONST(hostname);
147     name.u.dNSName.length = strlen(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.data = rk_UNCONST(email);
162     name.u.dNSName.length = strlen(email);
163 
164     return add_GeneralNames(&req->san, &name);
165 }
166 
167 
168 
169 int
170 _hx509_request_to_pkcs10(hx509_context context,
171 			 const hx509_request req,
172 			 const hx509_private_key signer,
173 			 heim_octet_string *request)
174 {
175     CertificationRequest r;
176     heim_octet_string data, os;
177     int ret;
178     size_t size;
179 
180     if (req->name == NULL) {
181 	hx509_set_error_string(context, 0, EINVAL,
182 			       "PKCS10 needs to have a subject");
183 	return EINVAL;
184     }
185 
186     memset(&r, 0, sizeof(r));
187     memset(request, 0, sizeof(*request));
188 
189     r.certificationRequestInfo.version = pkcs10_v1;
190 
191     ret = copy_Name(&req->name->der_name,
192 		    &r.certificationRequestInfo.subject);
193     if (ret)
194 	goto out;
195     ret = copy_SubjectPublicKeyInfo(&req->key,
196 				    &r.certificationRequestInfo.subjectPKInfo);
197     if (ret)
198 	goto out;
199     r.certificationRequestInfo.attributes =
200 	calloc(1, sizeof(*r.certificationRequestInfo.attributes));
201     if (r.certificationRequestInfo.attributes == NULL) {
202 	ret = ENOMEM;
203 	goto out;
204     }
205 
206     ASN1_MALLOC_ENCODE(CertificationRequestInfo, data.data, data.length,
207 		       &r.certificationRequestInfo, &size, ret);
208     if (ret)
209 	goto out;
210     if (data.length != size)
211 	abort();
212 
213     ret = _hx509_create_signature(context,
214 				  signer,
215 				  _hx509_crypto_default_sig_alg,
216 				  &data,
217 				  &r.signatureAlgorithm,
218 				  &os);
219     free(data.data);
220     if (ret)
221 	goto out;
222     r.signature.data = os.data;
223     r.signature.length = os.length * 8;
224 
225     ASN1_MALLOC_ENCODE(CertificationRequest, data.data, data.length,
226 		       &r, &size, ret);
227     if (ret)
228 	goto out;
229     if (data.length != size)
230 	abort();
231 
232     *request = data;
233 
234 out:
235     free_CertificationRequest(&r);
236 
237     return ret;
238 }
239 
240 int
241 _hx509_request_parse(hx509_context context,
242 		     const char *path,
243 		     hx509_request *req)
244 {
245     CertificationRequest r;
246     CertificationRequestInfo *rinfo;
247     hx509_name subject;
248     size_t len, size;
249     void *p;
250     int ret;
251 
252     if (strncmp(path, "PKCS10:", 7) != 0) {
253 	hx509_set_error_string(context, 0, HX509_UNSUPPORTED_OPERATION,
254 			       "unsupport type in %s", path);
255 	return HX509_UNSUPPORTED_OPERATION;
256     }
257     path += 7;
258 
259     /* XXX PEM request */
260 
261     ret = rk_undumpdata(path, &p, &len);
262     if (ret) {
263 	hx509_set_error_string(context, 0, ret, "Failed to map file %s", path);
264 	return ret;
265     }
266 
267     ret = decode_CertificationRequest(p, len, &r, &size);
268     rk_xfree(p);
269     if (ret) {
270 	hx509_set_error_string(context, 0, ret, "Failed to decode %s", path);
271 	return ret;
272     }
273 
274     ret = hx509_request_init(context, req);
275     if (ret) {
276 	free_CertificationRequest(&r);
277 	return ret;
278     }
279 
280     rinfo = &r.certificationRequestInfo;
281 
282     ret = hx509_request_set_SubjectPublicKeyInfo(context, *req,
283 						  &rinfo->subjectPKInfo);
284     if (ret) {
285 	free_CertificationRequest(&r);
286 	hx509_request_free(req);
287 	return ret;
288     }
289 
290     ret = _hx509_name_from_Name(&rinfo->subject, &subject);
291     if (ret) {
292 	free_CertificationRequest(&r);
293 	hx509_request_free(req);
294 	return ret;
295     }
296     ret = hx509_request_set_name(context, *req, subject);
297     hx509_name_free(&subject);
298     free_CertificationRequest(&r);
299     if (ret) {
300 	hx509_request_free(req);
301 	return ret;
302     }
303 
304     return 0;
305 }
306 
307 
308 int
309 _hx509_request_print(hx509_context context, hx509_request req, FILE *f)
310 {
311     int ret;
312 
313     if (req->name) {
314 	char *subject;
315 	ret = hx509_name_to_string(req->name, &subject);
316 	if (ret) {
317 	    hx509_set_error_string(context, 0, ret, "Failed to print name");
318 	    return ret;
319 	}
320         fprintf(f, "name: %s\n", subject);
321 	free(subject);
322     }
323 
324     return 0;
325 }
326 
327