]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - crypto/heimdal/lib/hx509/req.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / crypto / heimdal / lib / hx509 / req.c
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