Return to sshkey_builder.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / libstrongswan / plugins / sshkey |
1.1 misho 1: /* 2: * Copyright (C) 2013-2018 Tobias Brunner 3: * HSR Hochschule fuer Technik Rapperswil 4: * 5: * This program is free software; you can redistribute it and/or modify it 6: * under the terms of the GNU General Public License as published by the 7: * Free Software Foundation; either version 2 of the License, or (at your 8: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. 9: * 10: * This program is distributed in the hope that it will be useful, but 11: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 12: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13: * for more details. 14: */ 15: 16: #define _GNU_SOURCE /* for fmemopen() */ 17: #include <unistd.h> 18: #include <stdio.h> 19: #include <errno.h> 20: 21: #include "sshkey_builder.h" 22: 23: #include <asn1/oid.h> 24: #include <asn1/asn1.h> 25: #include <bio/bio_reader.h> 26: #include <utils/debug.h> 27: 28: #define ECDSA_PREFIX "ecdsa-sha2-" 29: 30: /** 31: * Parse an EC domain parameter identifier as defined in RFC 5656 32: */ 33: static chunk_t parse_ec_identifier(chunk_t identifier) 34: { 35: chunk_t oid = chunk_empty; 36: 37: if (chunk_equals(identifier, chunk_from_str("nistp256"))) 38: { 39: oid = asn1_build_known_oid(OID_PRIME256V1); 40: } 41: else if (chunk_equals(identifier, chunk_from_str("nistp384"))) 42: { 43: oid = asn1_build_known_oid(OID_SECT384R1); 44: } 45: else if (chunk_equals(identifier, chunk_from_str("nistp521"))) 46: { 47: oid = asn1_build_known_oid(OID_SECT521R1); 48: } 49: else 50: { 51: char ascii[64]; 52: 53: if (snprintf(ascii, sizeof(ascii), "%.*s", (int)identifier.len, 54: identifier.ptr) < sizeof(ascii)) 55: { 56: oid = asn1_wrap(ASN1_OID, "m", asn1_oid_from_string(ascii)); 57: } 58: } 59: return oid; 60: } 61: 62: /** 63: * Load a generic public key from an SSH key blob 64: */ 65: static sshkey_public_key_t *parse_public_key(chunk_t blob) 66: { 67: bio_reader_t *reader; 68: chunk_t format; 69: 70: reader = bio_reader_create(blob); 71: if (!reader->read_data32(reader, &format)) 72: { 73: DBG1(DBG_LIB, "invalid key format in SSH key"); 74: reader->destroy(reader); 75: return NULL; 76: } 77: if (chunk_equals(format, chunk_from_str("ssh-rsa"))) 78: { 79: chunk_t n, e; 80: 81: if (!reader->read_data32(reader, &e) || 82: !reader->read_data32(reader, &n)) 83: { 84: DBG1(DBG_LIB, "invalid RSA key in SSH key"); 85: reader->destroy(reader); 86: return NULL; 87: } 88: reader->destroy(reader); 89: return lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_RSA, 90: BUILD_RSA_MODULUS, n, BUILD_RSA_PUB_EXP, e, BUILD_END); 91: } 92: else if (chunk_equals(format, chunk_from_str("ssh-ed25519"))) 93: { 94: chunk_t ed_key; 95: 96: if (!reader->read_data32(reader, &ed_key)) 97: { 98: DBG1(DBG_LIB, "invalid Ed25519 key in SSH key"); 99: reader->destroy(reader); 100: return NULL; 101: } 102: reader->destroy(reader); 103: return lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ED25519, 104: BUILD_EDDSA_PUB, ed_key, BUILD_END); 105: } 106: else if (chunk_equals(format, chunk_from_str("ssh-ed448"))) 107: { 108: chunk_t ed_key; 109: 110: if (!reader->read_data32(reader, &ed_key)) 111: { 112: DBG1(DBG_LIB, "invalid Ed448 key in SSH key"); 113: reader->destroy(reader); 114: return NULL; 115: } 116: reader->destroy(reader); 117: return lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ED448, 118: BUILD_EDDSA_PUB, ed_key, BUILD_END); 119: } 120: else if (format.len > strlen(ECDSA_PREFIX) && 121: strpfx(format.ptr, ECDSA_PREFIX)) 122: { 123: chunk_t ec_blob, identifier, q, oid, encoded; 124: sshkey_public_key_t *key; 125: 126: ec_blob = reader->peek(reader); 127: reader->destroy(reader); 128: reader = bio_reader_create(ec_blob); 129: if (!reader->read_data32(reader, &identifier) || 130: !reader->read_data32(reader, &q)) 131: { 132: DBG1(DBG_LIB, "invalid ECDSA key in SSH key"); 133: reader->destroy(reader); 134: return NULL; 135: } 136: oid = parse_ec_identifier(identifier); 137: if (!oid.ptr) 138: { 139: DBG1(DBG_LIB, "invalid ECDSA key identifier in SSH key"); 140: reader->destroy(reader); 141: return NULL; 142: } 143: reader->destroy(reader); 144: /* build key from subjectPublicKeyInfo */ 145: encoded = asn1_wrap(ASN1_SEQUENCE, "mm", 146: asn1_wrap(ASN1_SEQUENCE, "mm", 147: asn1_build_known_oid(OID_EC_PUBLICKEY), oid), 148: asn1_bitstring("c", q)); 149: key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, 150: KEY_ECDSA, BUILD_BLOB_ASN1_DER, encoded, BUILD_END); 151: chunk_free(&encoded); 152: return key; 153: } 154: DBG1(DBG_LIB, "unsupported SSH key format %.*s", (int)format.len, 155: format.ptr); 156: reader->destroy(reader); 157: return NULL; 158: } 159: 160: /** 161: * Load SSH key from a FILE stream, closes the stream 162: */ 163: static sshkey_public_key_t *load_from_stream(FILE *file) 164: { 165: sshkey_public_key_t *public = NULL; 166: chunk_t blob = chunk_empty; 167: enumerator_t *enumerator; 168: char line[1024], *token; 169: 170: while (!public && fgets(line, sizeof(line), file)) 171: { /* the format is: ssh-<key-type> <key(base64)> <identifier> */ 172: if (!strpfx(line, "ssh-rsa") && !strpfx(line, ECDSA_PREFIX) && 173: !strpfx(line, "ssh-ed25519") && !strpfx(line, "ssh-ed448")) 174: { 175: continue; 176: } 177: enumerator = enumerator_create_token(line, " ", " "); 178: if (enumerator->enumerate(enumerator, &token) && 179: enumerator->enumerate(enumerator, &token)) 180: { 181: blob = chunk_from_base64(chunk_from_str(token), NULL); 182: } 183: enumerator->destroy(enumerator); 184: if (blob.ptr) 185: { 186: public = parse_public_key(blob); 187: chunk_free(&blob); 188: } 189: } 190: fclose(file); 191: return public; 192: } 193: 194: /** 195: * Load SSH key from a blob of data (most likely the content of a file) 196: */ 197: static sshkey_public_key_t *load_from_blob(chunk_t blob) 198: { 199: FILE *stream; 200: 201: stream = fmemopen(blob.ptr, blob.len, "r"); 202: if (!stream) 203: { 204: return NULL; 205: } 206: return load_from_stream(stream); 207: } 208: 209: /** 210: * Load SSH key from file 211: */ 212: static sshkey_public_key_t *load_from_file(char *file) 213: { 214: FILE *stream; 215: 216: stream = fopen(file, "r"); 217: if (!stream) 218: { 219: DBG1(DBG_LIB, " opening '%s' failed: %s", file, strerror(errno)); 220: return NULL; 221: } 222: return load_from_stream(stream); 223: } 224: 225: /** 226: * See header. 227: */ 228: sshkey_public_key_t *sshkey_public_key_load(key_type_t type, va_list args) 229: { 230: chunk_t sshkey = chunk_empty, blob = chunk_empty; 231: char *file = NULL; 232: 233: while (TRUE) 234: { 235: switch (va_arg(args, builder_part_t)) 236: { 237: case BUILD_BLOB_SSHKEY: 238: sshkey = va_arg(args, chunk_t); 239: continue; 240: case BUILD_FROM_FILE: 241: file = va_arg(args, char*); 242: continue; 243: case BUILD_BLOB: 244: blob = va_arg(args, chunk_t); 245: continue; 246: case BUILD_END: 247: break; 248: default: 249: return NULL; 250: } 251: break; 252: } 253: if (sshkey.ptr) 254: { 255: return parse_public_key(sshkey); 256: } 257: if (file) 258: { 259: return load_from_file(file); 260: } 261: if (blob.ptr) 262: { 263: return load_from_blob(blob); 264: } 265: return NULL; 266: } 267: 268: /** 269: * See header. 270: */ 271: certificate_t *sshkey_certificate_load(certificate_type_t type, va_list args) 272: { 273: certificate_t *cert; 274: public_key_t *key; 275: identification_t *subject = NULL; 276: char *file = NULL; 277: 278: while (TRUE) 279: { 280: switch (va_arg(args, builder_part_t)) 281: { 282: case BUILD_FROM_FILE: 283: file = va_arg(args, char*); 284: continue; 285: case BUILD_SUBJECT: 286: subject = va_arg(args, identification_t*); 287: continue; 288: case BUILD_END: 289: break; 290: default: 291: return NULL; 292: } 293: break; 294: } 295: if (!file || !subject) 296: { 297: return NULL; 298: } 299: key = (public_key_t*)load_from_file(file); 300: if (!key) 301: { 302: return NULL; 303: } 304: cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, 305: CERT_TRUSTED_PUBKEY, BUILD_PUBLIC_KEY, key, 306: BUILD_SUBJECT, subject, BUILD_END); 307: key->destroy(key); 308: return cert; 309: }