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>