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 327