Annotation of embedaddon/strongswan/src/libstrongswan/plugins/agent/agent_private_key.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * Copyright (C) 2013-2019 Tobias Brunner
                      3:  * Copyright (C) 2008-2009 Martin Willi
                      4:  * HSR Hochschule fuer Technik Rapperswil
                      5:  *
                      6:  * This program is free software; you can redistribute it and/or modify it
                      7:  * under the terms of the GNU General Public License as published by the
                      8:  * Free Software Foundation; either version 2 of the License, or (at your
                      9:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
                     10:  *
                     11:  * This program is distributed in the hope that it will be useful, but
                     12:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
                     13:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
                     14:  * for more details.
                     15:  */
                     16: 
                     17: #include "agent_private_key.h"
                     18: 
                     19: #include <stdlib.h>
                     20: #include <unistd.h>
                     21: #include <sys/types.h>
                     22: #include <sys/socket.h>
                     23: #include <sys/un.h>
                     24: #include <arpa/inet.h>
                     25: #include <errno.h>
                     26: 
                     27: #include <library.h>
                     28: #include <utils/chunk.h>
                     29: #include <utils/debug.h>
                     30: 
                     31: #ifndef UNIX_PATH_MAX
                     32: #define UNIX_PATH_MAX 108
                     33: #endif /* UNIX_PATH_MAX */
                     34: 
                     35: typedef struct private_agent_private_key_t private_agent_private_key_t;
                     36: typedef enum agent_msg_type_t agent_msg_type_t;
                     37: 
                     38: /**
                     39:  * Private data of a agent_private_key_t object.
                     40:  */
                     41: struct private_agent_private_key_t {
                     42:        /**
                     43:         * Public interface for this signer.
                     44:         */
                     45:        agent_private_key_t public;
                     46: 
                     47:        /**
                     48:         * Path to the UNIX socket
                     49:         */
                     50:        char *path;
                     51: 
                     52:        /**
                     53:         * public key encoded in SSH format
                     54:         */
                     55:        chunk_t key;
                     56: 
                     57:        /**
                     58:         * public key
                     59:         */
                     60:        public_key_t *pubkey;
                     61: 
                     62:        /**
                     63:         * keysize in bytes
                     64:         */
                     65:        size_t key_size;
                     66: 
                     67:        /**
                     68:         * reference count
                     69:         */
                     70:        refcount_t ref;
                     71: };
                     72: 
                     73: /**
                     74:  * Message types for ssh-agent protocol
                     75:  */
                     76: enum agent_msg_type_t {
                     77:        SSH_AGENT_FAILURE = 5,
                     78:        SSH_AGENT_SUCCESS =     6,
                     79:        SSH_AGENT_ID_REQUEST = 11,
                     80:        SSH_AGENT_ID_RESPONSE = 12,
                     81:        SSH_AGENT_SIGN_REQUEST = 13,
                     82:        SSH_AGENT_SIGN_RESPONSE = 14,
                     83: };
                     84: 
                     85: /**
                     86:  * Flags for signatures
                     87:  */
                     88: enum agent_signature_flags_t {
                     89:        SSH_AGENT_FLAG_SHA2_256 = 2,
                     90:        SSH_AGENT_FLAG_SHA2_512 = 4,
                     91: };
                     92: 
                     93: /**
                     94:  * read a byte from a blob
                     95:  */
                     96: static u_char read_byte(chunk_t *blob)
                     97: {
                     98:        u_char val;
                     99: 
                    100:        if (blob->len < sizeof(u_char))
                    101:        {
                    102:                return 0;
                    103:        }
                    104:        val = *(blob->ptr);
                    105:        *blob = chunk_skip(*blob, sizeof(u_char));
                    106:        return val;
                    107: }
                    108: 
                    109: /**
                    110:  * read a uint32_t from a blob
                    111:  */
                    112: static uint32_t read_uint32(chunk_t *blob)
                    113: {
                    114:        uint32_t val;
                    115: 
                    116:        if (blob->len < sizeof(uint32_t))
                    117:        {
                    118:                return 0;
                    119:        }
                    120:        val = ntohl(*(uint32_t*)blob->ptr);
                    121:        *blob = chunk_skip(*blob, sizeof(uint32_t));
                    122:        return val;
                    123: }
                    124: 
                    125: /**
                    126:  * read a ssh-agent "string" length/value from a blob
                    127:  */
                    128: static chunk_t read_string(chunk_t *blob)
                    129: {
                    130:        int len;
                    131:        chunk_t str;
                    132: 
                    133:        len = read_uint32(blob);
                    134:        if (len > blob->len)
                    135:        {
                    136:                return chunk_empty;
                    137:        }
                    138:        str = chunk_create(blob->ptr, len);
                    139:        *blob = chunk_skip(*blob, + len);
                    140:        return str;
                    141: }
                    142: 
                    143: /**
                    144:  * open socket connection to the ssh-agent
                    145:  */
                    146: static int open_connection(char *path)
                    147: {
                    148:        struct sockaddr_un addr;
                    149:        int s;
                    150: 
                    151:        s = socket(AF_UNIX, SOCK_STREAM, 0);
                    152:        if (s == -1)
                    153:        {
                    154:                DBG1(DBG_LIB, "opening ssh-agent socket %s failed: %s:", path,
                    155:                         strerror(errno));
                    156:                return -1;
                    157:        }
                    158: 
                    159:        addr.sun_family = AF_UNIX;
                    160:        addr.sun_path[UNIX_PATH_MAX - 1] = '\0';
                    161:        strncpy(addr.sun_path, path, UNIX_PATH_MAX - 1);
                    162: 
                    163:        if (connect(s, (struct sockaddr*)&addr, SUN_LEN(&addr)) != 0)
                    164:        {
                    165:                DBG1(DBG_LIB, "connecting to ssh-agent socket failed: %s",
                    166:                         strerror(errno));
                    167:                close(s);
                    168:                return -1;
                    169:        }
                    170:        return s;
                    171: }
                    172: 
                    173: /**
                    174:  * Get the first usable key from the agent
                    175:  */
                    176: static bool read_key(private_agent_private_key_t *this, public_key_t *pubkey)
                    177: {
                    178:        int socket, len;
                    179:        char buf[2048];
                    180:        chunk_t blob, key;
                    181:        bool success = FALSE;
                    182: 
                    183:        socket = open_connection(this->path);
                    184:        if (socket < 0)
                    185:        {
                    186:                return FALSE;
                    187:        }
                    188: 
                    189:        len = htonl(1);
                    190:        buf[0] = SSH_AGENT_ID_REQUEST;
                    191:        if (write(socket, &len, sizeof(len)) != sizeof(len) ||
                    192:                write(socket, &buf, 1) != 1)
                    193:        {
                    194:                DBG1(DBG_LIB, "writing to ssh-agent failed");
                    195:                goto done;
                    196:        }
                    197: 
                    198:        blob = chunk_create(buf, sizeof(buf));
                    199:        blob.len = read(socket, blob.ptr, blob.len);
                    200: 
                    201:        if (blob.len < sizeof(uint32_t) + sizeof(u_char) ||
                    202:                read_uint32(&blob) != blob.len ||
                    203:                read_byte(&blob) != SSH_AGENT_ID_RESPONSE)
                    204:        {
                    205:                DBG1(DBG_LIB, "received invalid ssh-agent identity response");
                    206:                goto done;
                    207:        }
                    208:        read_uint32(&blob);
                    209: 
                    210:        while (blob.len)
                    211:        {
                    212:                key = read_string(&blob);
                    213:                if (!key.len)
                    214:                {
                    215:                        break;
                    216:                }
                    217:                this->pubkey = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ANY,
                    218:                                                                                  BUILD_BLOB_SSHKEY, key, BUILD_END);
                    219:                if (!this->pubkey)
                    220:                {
                    221:                        continue;
                    222:                }
                    223:                if (pubkey && !private_key_belongs_to(&this->public.key, pubkey))
                    224:                {
                    225:                        this->pubkey->destroy(this->pubkey);
                    226:                        this->pubkey = NULL;
                    227:                        continue;
                    228:                }
                    229:                this->key = chunk_clone(key);
                    230:                success = TRUE;
                    231:                break;
                    232:        }
                    233: done:
                    234:        close(socket);
                    235:        return success;
                    236: }
                    237: 
                    238: static bool scheme_supported(private_agent_private_key_t *this,
                    239:                                                         signature_scheme_t scheme, uint32_t *flags,
                    240:                                                         char **prefix)
                    241: {
                    242:        switch (this->pubkey->get_type(this->pubkey))
                    243:        {
                    244:                case KEY_RSA:
                    245:                        switch (scheme)
                    246:                        {
                    247:                                case SIGN_RSA_EMSA_PKCS1_SHA1:
                    248:                                        *prefix = "ssh-rsa";
                    249:                                        return TRUE;
                    250:                                case SIGN_RSA_EMSA_PKCS1_SHA2_256:
                    251:                                        *flags |= SSH_AGENT_FLAG_SHA2_256;
                    252:                                        *prefix = "rsa-sha2-256";
                    253:                                        return TRUE;
                    254:                                case SIGN_RSA_EMSA_PKCS1_SHA2_512:
                    255:                                        *flags |= SSH_AGENT_FLAG_SHA2_512;
                    256:                                        *prefix = "rsa-sha2-512";
                    257:                                        return TRUE;
                    258:                                default:
                    259:                                        break;
                    260:                        }
                    261:                        return FALSE;
                    262:                case KEY_ED25519:
                    263:                        *prefix = "ssh-ed25519";
                    264:                        return scheme == SIGN_ED25519;
                    265:                case KEY_ED448:
                    266:                        *prefix = "ssh-ed448";
                    267:                        return scheme == SIGN_ED448;
                    268:                case KEY_ECDSA:
                    269:                        return scheme == SIGN_ECDSA_256 ||
                    270:                                   scheme == SIGN_ECDSA_384 ||
                    271:                                   scheme == SIGN_ECDSA_521;
                    272:                default:
                    273:                        return FALSE;
                    274:        }
                    275: }
                    276: 
                    277: METHOD(private_key_t, sign, bool,
                    278:        private_agent_private_key_t *this, signature_scheme_t scheme, void *params,
                    279:        chunk_t data, chunk_t *signature)
                    280: {
                    281:        key_type_t type;
                    282:        uint32_t len, flags = 0;
                    283:        char buf[2048], *prefix = NULL;
                    284:        chunk_t blob;
                    285:        int socket;
                    286:        bool success = FALSE;
                    287: 
                    288:        if (!scheme_supported(this, scheme, &flags, &prefix))
                    289:        {
                    290:                DBG1(DBG_LIB, "signature scheme %N not supported by ssh-agent",
                    291:                         signature_scheme_names, scheme);
                    292:                return FALSE;
                    293:        }
                    294: 
                    295:        socket = open_connection(this->path);
                    296:        if (socket < 0)
                    297:        {
                    298:                return FALSE;
                    299:        }
                    300: 
                    301:        len = htonl(1 + sizeof(uint32_t) * 3 + this->key.len + data.len);
                    302:        buf[0] = SSH_AGENT_SIGN_REQUEST;
                    303:        if (write(socket, &len, sizeof(len)) != sizeof(len) ||
                    304:                write(socket, &buf, 1) != 1)
                    305:        {
                    306:                DBG1(DBG_LIB, "writing to ssh-agent failed");
                    307:                goto done;
                    308:        }
                    309: 
                    310:        len = htonl(this->key.len);
                    311:        if (write(socket, &len, sizeof(len)) != sizeof(len) ||
                    312:                write(socket, this->key.ptr, this->key.len) != this->key.len)
                    313:        {
                    314:                DBG1(DBG_LIB, "writing to ssh-agent failed");
                    315:                goto done;
                    316:        }
                    317: 
                    318:        len = htonl(data.len);
                    319:        if (write(socket, &len, sizeof(len)) != sizeof(len) ||
                    320:                write(socket, data.ptr, data.len) != data.len)
                    321:        {
                    322:                DBG1(DBG_LIB, "writing to ssh-agent failed");
                    323:                goto done;
                    324:        }
                    325: 
                    326:        flags = htonl(flags);
                    327:        if (write(socket, &flags, sizeof(flags)) != sizeof(flags))
                    328:        {
                    329:                DBG1(DBG_LIB, "writing to ssh-agent failed");
                    330:                goto done;
                    331:        }
                    332: 
                    333:        blob = chunk_create(buf, sizeof(buf));
                    334:        blob.len = read(socket, blob.ptr, blob.len);
                    335:        if (blob.len < sizeof(uint32_t) + sizeof(u_char) ||
                    336:                read_uint32(&blob) != blob.len ||
                    337:                read_byte(&blob) != SSH_AGENT_SIGN_RESPONSE)
                    338:        {
                    339:                DBG1(DBG_LIB, "received invalid ssh-agent signature response");
                    340:                goto done;
                    341:        }
                    342:        /* parse length */
                    343:        blob = read_string(&blob);
                    344:        /* verify type */
                    345:        if (prefix && !chunk_equals(read_string(&blob), chunk_from_str(prefix)))
                    346:        {
                    347:                DBG1(DBG_LIB, "ssh-agent didn't return requested %s signature", prefix);
                    348:                goto done;
                    349:        }
                    350:        type = this->pubkey->get_type(this->pubkey);
                    351:        if (type == KEY_RSA || type == KEY_ED25519 || type == KEY_ED448)
                    352:        {       /* for RSA/EdDSA, the signature has no special encoding */
                    353:                blob = read_string(&blob);
                    354:                if (blob.len)
                    355:                {
                    356:                        *signature = chunk_clone(blob);
                    357:                        success = TRUE;
                    358:                }
                    359:        }
                    360:        else
                    361:        {       /* parse ECDSA signatures */
                    362:                blob = read_string(&blob);
                    363:                if (blob.len)
                    364:                {
                    365:                        chunk_t r, s;
                    366: 
                    367:                        r = read_string(&blob);
                    368:                        s = read_string(&blob);
                    369:                        if (r.len && s.len)
                    370:                        {
                    371:                                *signature = chunk_cat("cc", r, s);
                    372:                                success = TRUE;
                    373:                        }
                    374:                }
                    375:        }
                    376:        if (!success)
                    377:        {
                    378:                DBG1(DBG_LIB, "received invalid ssh-agent signature response");
                    379:        }
                    380: 
                    381: done:
                    382:        close(socket);
                    383:        return success;
                    384: }
                    385: 
                    386: METHOD(private_key_t, get_type, key_type_t,
                    387:        private_agent_private_key_t *this)
                    388: {
                    389:        return this->pubkey->get_type(this->pubkey);
                    390: }
                    391: 
                    392: METHOD(private_key_t, decrypt, bool,
                    393:        private_agent_private_key_t *this, encryption_scheme_t scheme,
                    394:        chunk_t crypto, chunk_t *plain)
                    395: {
                    396:        DBG1(DBG_LIB, "private key decryption not supported by ssh-agent");
                    397:        return FALSE;
                    398: }
                    399: 
                    400: METHOD(private_key_t, get_keysize, int,
                    401:        private_agent_private_key_t *this)
                    402: {
                    403:        return this->pubkey->get_keysize(this->pubkey);
                    404: }
                    405: 
                    406: /**
                    407:  * Private data for RSA scheme enumerator
                    408:  */
                    409: typedef struct {
                    410:        enumerator_t public;
                    411:        int index;
                    412:        bool reverse;
                    413: } scheme_enumerator_t;
                    414: 
                    415: static signature_params_t rsa_schemes[] = {
                    416:        { .scheme = SIGN_RSA_EMSA_PKCS1_SHA2_256 },
                    417:        { .scheme = SIGN_RSA_EMSA_PKCS1_SHA2_512 },
                    418: };
                    419: 
                    420: METHOD(enumerator_t, enumerate_rsa_scheme, bool,
                    421:        scheme_enumerator_t *this, va_list args)
                    422: {
                    423:        signature_params_t **params;
                    424: 
                    425:        VA_ARGS_VGET(args, params);
                    426: 
                    427:        if ((this->reverse && --this->index >= 0) ||
                    428:           (!this->reverse && ++this->index < countof(rsa_schemes)))
                    429:        {
                    430:                *params = &rsa_schemes[this->index];
                    431:                return TRUE;
                    432:        }
                    433:        return FALSE;
                    434: }
                    435: 
                    436: /**
                    437:  * Create an enumerator for the supported RSA signature schemes
                    438:  */
                    439: static enumerator_t *create_rsa_enumerator(private_agent_private_key_t *this)
                    440: {
                    441:        scheme_enumerator_t *enumerator;
                    442: 
                    443:        INIT(enumerator,
                    444:                .public = {
                    445:                        .enumerate = enumerator_enumerate_default,
                    446:                        .venumerate = _enumerate_rsa_scheme,
                    447:                        .destroy = (void*)free,
                    448:                },
                    449:                .index = -1,
                    450:                .reverse = FALSE,
                    451:        );
                    452:        /* propose SHA-512 first for larger keys */
                    453:        if (get_keysize(this) > 3072)
                    454:        {
                    455:                enumerator->index = countof(rsa_schemes);
                    456:                enumerator->reverse = TRUE;
                    457:        }
                    458:        return &enumerator->public;
                    459: }
                    460: 
                    461: METHOD(private_key_t, supported_signature_schemes, enumerator_t*,
                    462:        private_agent_private_key_t *this)
                    463: {
                    464:        key_type_t type = get_type(this);
                    465: 
                    466:        switch (type)
                    467:        {
                    468:                case KEY_RSA:
                    469:                        return create_rsa_enumerator(this);
                    470:                case KEY_ED25519:
                    471:                case KEY_ED448:
                    472:                case KEY_ECDSA:
                    473:                        return signature_schemes_for_key(type, get_keysize(this));
                    474:                default:
                    475:                        break;
                    476:        }
                    477:        return enumerator_create_empty();
                    478: }
                    479: 
                    480: METHOD(private_key_t, get_public_key, public_key_t*,
                    481:        private_agent_private_key_t *this)
                    482: {
                    483:        return this->pubkey->get_ref(this->pubkey);
                    484: }
                    485: 
                    486: METHOD(private_key_t, get_encoding, bool,
                    487:        private_agent_private_key_t *this, cred_encoding_type_t type,
                    488:        chunk_t *encoding)
                    489: {
                    490:        return FALSE;
                    491: }
                    492: 
                    493: METHOD(private_key_t, get_fingerprint, bool,
                    494:        private_agent_private_key_t *this, cred_encoding_type_t type, chunk_t *fp)
                    495: {
                    496:        return this->pubkey->get_fingerprint(this->pubkey, type, fp);
                    497: }
                    498: 
                    499: METHOD(private_key_t, get_ref, private_key_t*,
                    500:        private_agent_private_key_t *this)
                    501: {
                    502:        ref_get(&this->ref);
                    503:        return &this->public.key;
                    504: }
                    505: 
                    506: METHOD(private_key_t, destroy, void,
                    507:        private_agent_private_key_t *this)
                    508: {
                    509:        if (ref_put(&this->ref))
                    510:        {
                    511:                chunk_free(&this->key);
                    512:                DESTROY_IF(this->pubkey);
                    513:                free(this->path);
                    514:                free(this);
                    515:        }
                    516: }
                    517: 
                    518: /**
                    519:  * See header.
                    520:  */
                    521: agent_private_key_t *agent_private_key_open(key_type_t type, va_list args)
                    522: {
                    523:        private_agent_private_key_t *this;
                    524:        public_key_t *pubkey = NULL;
                    525:        char *path = NULL;
                    526: 
                    527:        while (TRUE)
                    528:        {
                    529:                switch (va_arg(args, builder_part_t))
                    530:                {
                    531:                        case BUILD_AGENT_SOCKET:
                    532:                                path = va_arg(args, char*);
                    533:                                continue;
                    534:                        case BUILD_PUBLIC_KEY:
                    535:                                pubkey = va_arg(args, public_key_t*);
                    536:                                continue;
                    537:                        case BUILD_END:
                    538:                                break;
                    539:                        default:
                    540:                                return NULL;
                    541:                }
                    542:                break;
                    543:        }
                    544:        if (!path)
                    545:        {
                    546:                return NULL;
                    547:        }
                    548: 
                    549:        INIT(this,
                    550:                .public = {
                    551:                        .key = {
                    552:                                .get_type = _get_type,
                    553:                                .supported_signature_schemes = _supported_signature_schemes,
                    554:                                .sign = _sign,
                    555:                                .decrypt = _decrypt,
                    556:                                .get_keysize = _get_keysize,
                    557:                                .get_public_key = _get_public_key,
                    558:                                .belongs_to = private_key_belongs_to,
                    559:                                .equals = private_key_equals,
                    560:                                .get_fingerprint = _get_fingerprint,
                    561:                                .has_fingerprint = private_key_has_fingerprint,
                    562:                                .get_encoding = _get_encoding,
                    563:                                .get_ref = _get_ref,
                    564:                                .destroy = _destroy,
                    565:                        },
                    566:                },
                    567:                .path = strdup(path),
                    568:                .ref = 1,
                    569:        );
                    570: 
                    571:        if (!read_key(this, pubkey))
                    572:        {
                    573:                destroy(this);
                    574:                return NULL;
                    575:        }
                    576:        return &this->public;
                    577: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>