Annotation of embedaddon/strongswan/src/libstrongswan/plugins/sshkey/sshkey_builder.c, revision 1.1
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: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>