1178825Sdfr/*
2233294Sstas * Copyright (c) 2006 Kungliga Tekniska H��gskolan
3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden).
4233294Sstas * All rights reserved.
5178825Sdfr *
6233294Sstas * Redistribution and use in source and binary forms, with or without
7233294Sstas * modification, are permitted provided that the following conditions
8233294Sstas * are met:
9178825Sdfr *
10233294Sstas * 1. Redistributions of source code must retain the above copyright
11233294Sstas *    notice, this list of conditions and the following disclaimer.
12178825Sdfr *
13233294Sstas * 2. Redistributions in binary form must reproduce the above copyright
14233294Sstas *    notice, this list of conditions and the following disclaimer in the
15233294Sstas *    documentation and/or other materials provided with the distribution.
16178825Sdfr *
17233294Sstas * 3. Neither the name of the Institute nor the names of its contributors
18233294Sstas *    may be used to endorse or promote products derived from this software
19233294Sstas *    without specific prior written permission.
20178825Sdfr *
21233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24233294Sstas * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31233294Sstas * SUCH DAMAGE.
32178825Sdfr */
33178825Sdfr
34178825Sdfr#include "hx_locl.h"
35178825Sdfr#include <pkcs10_asn1.h>
36178825Sdfr
37178825Sdfrstruct hx509_request_data {
38178825Sdfr    hx509_name name;
39178825Sdfr    SubjectPublicKeyInfo key;
40178825Sdfr    ExtKeyUsage eku;
41178825Sdfr    GeneralNames san;
42178825Sdfr};
43178825Sdfr
44178825Sdfr/*
45178825Sdfr *
46178825Sdfr */
47178825Sdfr
48178825Sdfrint
49233294Sstashx509_request_init(hx509_context context, hx509_request *req)
50178825Sdfr{
51178825Sdfr    *req = calloc(1, sizeof(**req));
52178825Sdfr    if (*req == NULL)
53178825Sdfr	return ENOMEM;
54178825Sdfr
55178825Sdfr    return 0;
56178825Sdfr}
57178825Sdfr
58178825Sdfrvoid
59233294Sstashx509_request_free(hx509_request *req)
60178825Sdfr{
61178825Sdfr    if ((*req)->name)
62178825Sdfr	hx509_name_free(&(*req)->name);
63178825Sdfr    free_SubjectPublicKeyInfo(&(*req)->key);
64178825Sdfr    free_ExtKeyUsage(&(*req)->eku);
65178825Sdfr    free_GeneralNames(&(*req)->san);
66178825Sdfr    memset(*req, 0, sizeof(**req));
67178825Sdfr    free(*req);
68178825Sdfr    *req = NULL;
69178825Sdfr}
70178825Sdfr
71178825Sdfrint
72233294Sstashx509_request_set_name(hx509_context context,
73178825Sdfr			hx509_request req,
74178825Sdfr			hx509_name name)
75178825Sdfr{
76178825Sdfr    if (req->name)
77178825Sdfr	hx509_name_free(&req->name);
78178825Sdfr    if (name) {
79178825Sdfr	int ret = hx509_name_copy(context, name, &req->name);
80178825Sdfr	if (ret)
81178825Sdfr	    return ret;
82178825Sdfr    }
83178825Sdfr    return 0;
84178825Sdfr}
85178825Sdfr
86178825Sdfrint
87233294Sstashx509_request_get_name(hx509_context context,
88178825Sdfr			hx509_request req,
89178825Sdfr			hx509_name *name)
90178825Sdfr{
91178825Sdfr    if (req->name == NULL) {
92178825Sdfr	hx509_set_error_string(context, 0, EINVAL, "Request have no name");
93178825Sdfr	return EINVAL;
94178825Sdfr    }
95178825Sdfr    return hx509_name_copy(context, req->name, name);
96178825Sdfr}
97178825Sdfr
98178825Sdfrint
99233294Sstashx509_request_set_SubjectPublicKeyInfo(hx509_context context,
100178825Sdfr					hx509_request req,
101178825Sdfr					const SubjectPublicKeyInfo *key)
102178825Sdfr{
103178825Sdfr    free_SubjectPublicKeyInfo(&req->key);
104178825Sdfr    return copy_SubjectPublicKeyInfo(key, &req->key);
105178825Sdfr}
106178825Sdfr
107178825Sdfrint
108233294Sstashx509_request_get_SubjectPublicKeyInfo(hx509_context context,
109178825Sdfr					hx509_request req,
110178825Sdfr					SubjectPublicKeyInfo *key)
111178825Sdfr{
112178825Sdfr    return copy_SubjectPublicKeyInfo(&req->key, key);
113178825Sdfr}
114178825Sdfr
115178825Sdfrint
116178825Sdfr_hx509_request_add_eku(hx509_context context,
117178825Sdfr		       hx509_request req,
118178825Sdfr		       const heim_oid *oid)
119178825Sdfr{
120178825Sdfr    void *val;
121178825Sdfr    int ret;
122178825Sdfr
123178825Sdfr    val = realloc(req->eku.val, sizeof(req->eku.val[0]) * (req->eku.len + 1));
124178825Sdfr    if (val == NULL)
125178825Sdfr	return ENOMEM;
126178825Sdfr    req->eku.val = val;
127178825Sdfr
128178825Sdfr    ret = der_copy_oid(oid, &req->eku.val[req->eku.len]);
129178825Sdfr    if (ret)
130178825Sdfr	return ret;
131178825Sdfr
132178825Sdfr    req->eku.len += 1;
133178825Sdfr
134178825Sdfr    return 0;
135178825Sdfr}
136178825Sdfr
137178825Sdfrint
138178825Sdfr_hx509_request_add_dns_name(hx509_context context,
139178825Sdfr			    hx509_request req,
140178825Sdfr			    const char *hostname)
141178825Sdfr{
142178825Sdfr    GeneralName name;
143178825Sdfr
144178825Sdfr    memset(&name, 0, sizeof(name));
145178825Sdfr    name.element = choice_GeneralName_dNSName;
146233294Sstas    name.u.dNSName.data = rk_UNCONST(hostname);
147233294Sstas    name.u.dNSName.length = strlen(hostname);
148178825Sdfr
149178825Sdfr    return add_GeneralNames(&req->san, &name);
150178825Sdfr}
151178825Sdfr
152178825Sdfrint
153178825Sdfr_hx509_request_add_email(hx509_context context,
154178825Sdfr			 hx509_request req,
155178825Sdfr			 const char *email)
156178825Sdfr{
157178825Sdfr    GeneralName name;
158178825Sdfr
159178825Sdfr    memset(&name, 0, sizeof(name));
160178825Sdfr    name.element = choice_GeneralName_rfc822Name;
161233294Sstas    name.u.dNSName.data = rk_UNCONST(email);
162233294Sstas    name.u.dNSName.length = strlen(email);
163178825Sdfr
164178825Sdfr    return add_GeneralNames(&req->san, &name);
165178825Sdfr}
166178825Sdfr
167178825Sdfr
168178825Sdfr
169178825Sdfrint
170178825Sdfr_hx509_request_to_pkcs10(hx509_context context,
171178825Sdfr			 const hx509_request req,
172178825Sdfr			 const hx509_private_key signer,
173178825Sdfr			 heim_octet_string *request)
174178825Sdfr{
175178825Sdfr    CertificationRequest r;
176178825Sdfr    heim_octet_string data, os;
177178825Sdfr    int ret;
178178825Sdfr    size_t size;
179178825Sdfr
180178825Sdfr    if (req->name == NULL) {
181178825Sdfr	hx509_set_error_string(context, 0, EINVAL,
182178825Sdfr			       "PKCS10 needs to have a subject");
183178825Sdfr	return EINVAL;
184178825Sdfr    }
185178825Sdfr
186178825Sdfr    memset(&r, 0, sizeof(r));
187178825Sdfr    memset(request, 0, sizeof(*request));
188178825Sdfr
189178825Sdfr    r.certificationRequestInfo.version = pkcs10_v1;
190178825Sdfr
191178825Sdfr    ret = copy_Name(&req->name->der_name,
192178825Sdfr		    &r.certificationRequestInfo.subject);
193178825Sdfr    if (ret)
194178825Sdfr	goto out;
195178825Sdfr    ret = copy_SubjectPublicKeyInfo(&req->key,
196178825Sdfr				    &r.certificationRequestInfo.subjectPKInfo);
197178825Sdfr    if (ret)
198178825Sdfr	goto out;
199233294Sstas    r.certificationRequestInfo.attributes =
200178825Sdfr	calloc(1, sizeof(*r.certificationRequestInfo.attributes));
201178825Sdfr    if (r.certificationRequestInfo.attributes == NULL) {
202178825Sdfr	ret = ENOMEM;
203178825Sdfr	goto out;
204178825Sdfr    }
205178825Sdfr
206233294Sstas    ASN1_MALLOC_ENCODE(CertificationRequestInfo, data.data, data.length,
207178825Sdfr		       &r.certificationRequestInfo, &size, ret);
208178825Sdfr    if (ret)
209178825Sdfr	goto out;
210178825Sdfr    if (data.length != size)
211178825Sdfr	abort();
212178825Sdfr
213178825Sdfr    ret = _hx509_create_signature(context,
214178825Sdfr				  signer,
215178825Sdfr				  _hx509_crypto_default_sig_alg,
216178825Sdfr				  &data,
217178825Sdfr				  &r.signatureAlgorithm,
218178825Sdfr				  &os);
219178825Sdfr    free(data.data);
220178825Sdfr    if (ret)
221178825Sdfr	goto out;
222178825Sdfr    r.signature.data = os.data;
223178825Sdfr    r.signature.length = os.length * 8;
224178825Sdfr
225178825Sdfr    ASN1_MALLOC_ENCODE(CertificationRequest, data.data, data.length,
226178825Sdfr		       &r, &size, ret);
227178825Sdfr    if (ret)
228178825Sdfr	goto out;
229178825Sdfr    if (data.length != size)
230178825Sdfr	abort();
231178825Sdfr
232178825Sdfr    *request = data;
233178825Sdfr
234178825Sdfrout:
235178825Sdfr    free_CertificationRequest(&r);
236178825Sdfr
237178825Sdfr    return ret;
238178825Sdfr}
239178825Sdfr
240178825Sdfrint
241233294Sstas_hx509_request_parse(hx509_context context,
242178825Sdfr		     const char *path,
243178825Sdfr		     hx509_request *req)
244178825Sdfr{
245178825Sdfr    CertificationRequest r;
246178825Sdfr    CertificationRequestInfo *rinfo;
247178825Sdfr    hx509_name subject;
248178825Sdfr    size_t len, size;
249178825Sdfr    void *p;
250178825Sdfr    int ret;
251178825Sdfr
252178825Sdfr    if (strncmp(path, "PKCS10:", 7) != 0) {
253178825Sdfr	hx509_set_error_string(context, 0, HX509_UNSUPPORTED_OPERATION,
254178825Sdfr			       "unsupport type in %s", path);
255178825Sdfr	return HX509_UNSUPPORTED_OPERATION;
256178825Sdfr    }
257178825Sdfr    path += 7;
258178825Sdfr
259178825Sdfr    /* XXX PEM request */
260178825Sdfr
261233294Sstas    ret = rk_undumpdata(path, &p, &len);
262178825Sdfr    if (ret) {
263178825Sdfr	hx509_set_error_string(context, 0, ret, "Failed to map file %s", path);
264178825Sdfr	return ret;
265178825Sdfr    }
266178825Sdfr
267178825Sdfr    ret = decode_CertificationRequest(p, len, &r, &size);
268233294Sstas    rk_xfree(p);
269178825Sdfr    if (ret) {
270178825Sdfr	hx509_set_error_string(context, 0, ret, "Failed to decode %s", path);
271178825Sdfr	return ret;
272178825Sdfr    }
273178825Sdfr
274233294Sstas    ret = hx509_request_init(context, req);
275178825Sdfr    if (ret) {
276178825Sdfr	free_CertificationRequest(&r);
277178825Sdfr	return ret;
278178825Sdfr    }
279178825Sdfr
280178825Sdfr    rinfo = &r.certificationRequestInfo;
281178825Sdfr
282233294Sstas    ret = hx509_request_set_SubjectPublicKeyInfo(context, *req,
283178825Sdfr						  &rinfo->subjectPKInfo);
284178825Sdfr    if (ret) {
285178825Sdfr	free_CertificationRequest(&r);
286233294Sstas	hx509_request_free(req);
287178825Sdfr	return ret;
288178825Sdfr    }
289178825Sdfr
290178825Sdfr    ret = _hx509_name_from_Name(&rinfo->subject, &subject);
291178825Sdfr    if (ret) {
292178825Sdfr	free_CertificationRequest(&r);
293233294Sstas	hx509_request_free(req);
294178825Sdfr	return ret;
295178825Sdfr    }
296233294Sstas    ret = hx509_request_set_name(context, *req, subject);
297178825Sdfr    hx509_name_free(&subject);
298178825Sdfr    free_CertificationRequest(&r);
299178825Sdfr    if (ret) {
300233294Sstas	hx509_request_free(req);
301178825Sdfr	return ret;
302178825Sdfr    }
303178825Sdfr
304178825Sdfr    return 0;
305178825Sdfr}
306178825Sdfr
307178825Sdfr
308178825Sdfrint
309178825Sdfr_hx509_request_print(hx509_context context, hx509_request req, FILE *f)
310178825Sdfr{
311178825Sdfr    int ret;
312178825Sdfr
313178825Sdfr    if (req->name) {
314178825Sdfr	char *subject;
315178825Sdfr	ret = hx509_name_to_string(req->name, &subject);
316178825Sdfr	if (ret) {
317178825Sdfr	    hx509_set_error_string(context, 0, ret, "Failed to print name");
318178825Sdfr	    return ret;
319178825Sdfr	}
320178825Sdfr        fprintf(f, "name: %s\n", subject);
321178825Sdfr	free(subject);
322178825Sdfr    }
323233294Sstas
324178825Sdfr    return 0;
325178825Sdfr}
326178825Sdfr
327