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