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
37struct hx509_request_data {
38    hx509_name name;
39    SubjectPublicKeyInfo key;
40    ExtKeyUsage eku;
41    GeneralNames san;
42};
43
44/*
45 *
46 */
47
48int
49hx509_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
58void
59hx509_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
71int
72hx509_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
86int
87hx509_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
98int
99hx509_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
107int
108hx509_request_get_SubjectPublicKeyInfo(hx509_context context,
109					hx509_request req,
110					SubjectPublicKeyInfo *key)
111{
112    return copy_SubjectPublicKeyInfo(&req->key, key);
113}
114
115int
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
137int
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
152int
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
169int
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
234out:
235    free_CertificationRequest(&r);
236
237    return ret;
238}
239
240int
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
308int
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