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