Annotation of embedaddon/strongswan/src/libstrongswan/plugins/sshkey/sshkey_builder.c, revision 1.1.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>