Annotation of embedaddon/strongswan/src/libstrongswan/plugins/curve25519/curve25519_public_key.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * Copyright (C) 2018 Tobias Brunner
                      3:  * Copyright (C) 2016 Andreas Steffen
                      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 "curve25519_public_key.h"
                     18: #include "ref10/ref10.h"
                     19: 
                     20: #include <asn1/asn1.h>
                     21: #include <asn1/asn1_parser.h>
                     22: #include <asn1/oid.h>
                     23: 
                     24: typedef struct private_curve25519_public_key_t private_curve25519_public_key_t;
                     25: 
                     26: /**
                     27:  * Private data structure with signing context.
                     28:  */
                     29: struct private_curve25519_public_key_t {
                     30:        /**
                     31:         * Public interface for this signer.
                     32:         */
                     33:        curve25519_public_key_t public;
                     34: 
                     35:        /**
                     36:         * Ed25519 public key
                     37:         */
                     38:        chunk_t pubkey;
                     39: 
                     40:        /**
                     41:         * Reference counter
                     42:         */
                     43:        refcount_t ref;
                     44: };
                     45: 
                     46: METHOD(public_key_t, get_type, key_type_t,
                     47:        private_curve25519_public_key_t *this)
                     48: {
                     49:        return KEY_ED25519;
                     50: }
                     51: 
                     52: /* L = 2^252+27742317777372353535851937790883648493 in little-endian form */
                     53: static chunk_t curve25519_order = chunk_from_chars(
                     54:                                                                0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58,
                     55:                                                                0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14,
                     56:                                                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                     57:                                                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10);
                     58: 
                     59: METHOD(public_key_t, verify, bool,
                     60:        private_curve25519_public_key_t *this, signature_scheme_t scheme,
                     61:        void *params, chunk_t data, chunk_t signature)
                     62: {
                     63:        hasher_t *hasher;
                     64:        uint8_t d = 0, k[HASH_SIZE_SHA512], r[32], *sig;
                     65:        int i;
                     66:        ge_p3 A;
                     67:        ge_p2 R;
                     68: 
                     69:        if (scheme != SIGN_ED25519)
                     70:        {
                     71:                DBG1(DBG_LIB, "signature scheme %N not supported by Ed25519",
                     72:                         signature_scheme_names, scheme);
                     73:                return FALSE;
                     74:        }
                     75: 
                     76:        if (signature.len != 64)
                     77:        {
                     78:                DBG1(DBG_LIB, "size of Ed25519 signature is not 64 bytes");
                     79:                return FALSE;
                     80:        }
                     81:        sig = signature.ptr;
                     82: 
                     83:        if (sig[63] & 0xe0)
                     84:        {
                     85:                DBG1(DBG_LIB, "the three most significant bits of Ed25519 signature "
                     86:                         "are not zero");
                     87:                return FALSE;
                     88:        }
                     89: 
                     90:        if (ge_frombytes_negate_vartime(&A, this->pubkey.ptr) != 0)
                     91:        {
                     92:                return FALSE;
                     93:        }
                     94: 
                     95:        /* check for all-zeroes public key */
                     96:        for (i = 0; i < 32; i++)
                     97:        {
                     98:                d |= this->pubkey.ptr[i];
                     99:        }
                    100:        if (!d)
                    101:        {
                    102:                return FALSE;
                    103:        }
                    104:        /* make sure 0 <= s < L, as per RFC 8032, section 5.1.7 to prevent signature
                    105:         * malleability.  Due to the three-bit check above (forces s < 2^253) there
                    106:         * is not that much room, but adding L once works with most signatures */
                    107:        for (i = 31; ; i--)
                    108:        {
                    109:                if (sig[i+32] < curve25519_order.ptr[i])
                    110:                {
                    111:                        break;
                    112:                }
                    113:                else if (sig[i+32] > curve25519_order.ptr[i] || i == 0)
                    114:                {
                    115:                        return FALSE;
                    116:                }
                    117:        }
                    118: 
                    119:        hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA512);
                    120:        if (!hasher)
                    121:        {
                    122:                return FALSE;
                    123:        }
                    124:        if (!hasher->get_hash(hasher, chunk_create(sig, 32), NULL) ||
                    125:                !hasher->get_hash(hasher, this->pubkey, NULL) ||
                    126:                !hasher->get_hash(hasher, data, k))
                    127:        {
                    128:                hasher->destroy(hasher);
                    129:                return FALSE;
                    130:        }
                    131:        hasher->destroy(hasher);
                    132: 
                    133:        sc_reduce(k);
                    134:        ge_double_scalarmult_vartime(&R, k, &A, sig + 32);
                    135:        ge_tobytes(r, &R);
                    136: 
                    137:        return memeq_const(sig, r, 32);
                    138: }
                    139: 
                    140: METHOD(public_key_t, encrypt_, bool,
                    141:        private_curve25519_public_key_t *this, encryption_scheme_t scheme,
                    142:        chunk_t plain, chunk_t *crypto)
                    143: {
                    144:        DBG1(DBG_LIB, "encryption scheme %N not supported", encryption_scheme_names,
                    145:                 scheme);
                    146:        return FALSE;
                    147: }
                    148: 
                    149: METHOD(public_key_t, get_keysize, int,
                    150:        private_curve25519_public_key_t *this)
                    151: {
                    152:        return 8 * ED25519_KEY_LEN;
                    153: }
                    154: 
                    155: METHOD(public_key_t, get_encoding, bool,
                    156:        private_curve25519_public_key_t *this, cred_encoding_type_t type,
                    157:        chunk_t *encoding)
                    158: {
                    159:        bool success = TRUE;
                    160: 
                    161:        *encoding = curve25519_public_key_info_encode(this->pubkey);
                    162: 
                    163:        if (type != PUBKEY_SPKI_ASN1_DER)
                    164:        {
                    165:                chunk_t asn1_encoding = *encoding;
                    166: 
                    167:                success = lib->encoding->encode(lib->encoding, type,
                    168:                                                NULL, encoding, CRED_PART_EDDSA_PUB_ASN1_DER,
                    169:                                                asn1_encoding, CRED_PART_END);
                    170:                chunk_clear(&asn1_encoding);
                    171:        }
                    172:        return success;
                    173: }
                    174: 
                    175: METHOD(public_key_t, get_fingerprint, bool,
                    176:        private_curve25519_public_key_t *this, cred_encoding_type_t type,
                    177:        chunk_t *fp)
                    178: {
                    179:        bool success;
                    180: 
                    181:        if (lib->encoding->get_cache(lib->encoding, type, this, fp))
                    182:        {
                    183:                return TRUE;
                    184:        }
                    185:        success = curve25519_public_key_fingerprint(this->pubkey, type, fp);
                    186:        if (success)
                    187:        {
                    188:                lib->encoding->cache(lib->encoding, type, this, *fp);
                    189:        }
                    190:        return success;
                    191: }
                    192: 
                    193: METHOD(public_key_t, get_ref, public_key_t*,
                    194:        private_curve25519_public_key_t *this)
                    195: {
                    196:        ref_get(&this->ref);
                    197:        return &this->public.key;
                    198: }
                    199: 
                    200: METHOD(public_key_t, destroy, void,
                    201:        private_curve25519_public_key_t *this)
                    202: {
                    203:        if (ref_put(&this->ref))
                    204:        {
                    205:                lib->encoding->clear_cache(lib->encoding, this);
                    206:                free(this->pubkey.ptr);
                    207:                free(this);
                    208:        }
                    209: }
                    210: 
                    211: /**
                    212:  * ASN.1 definition of an Ed25519 public key
                    213:  */
                    214: static const asn1Object_t pubkeyObjects[] = {
                    215:        { 0, "subjectPublicKeyInfo",ASN1_SEQUENCE,              ASN1_NONE }, /*  0 */
                    216:        { 1,   "algorithm",                     ASN1_EOC,                       ASN1_RAW  }, /*  1 */
                    217:        { 1,   "subjectPublicKey",      ASN1_BIT_STRING,        ASN1_BODY }, /*  2 */
                    218:        { 0, "exit",                            ASN1_EOC,                       ASN1_EXIT }
                    219: };
                    220: 
                    221: #define ED25519_SUBJECT_PUBLIC_KEY_ALGORITHM   1
                    222: #define ED25519_SUBJECT_PUBLIC_KEY                             2
                    223: 
                    224: /**
                    225:  * Parse the ASN.1-encoded subjectPublicKeyInfo
                    226:  */
                    227: static bool parse_public_key_info(private_curve25519_public_key_t *this,
                    228:                                                                  chunk_t blob)
                    229: {
                    230:        asn1_parser_t *parser;
                    231:        chunk_t object;
                    232:        bool success = FALSE;
                    233:        int objectID, oid;
                    234: 
                    235:        parser = asn1_parser_create(pubkeyObjects, blob);
                    236: 
                    237:        while (parser->iterate(parser, &objectID, &object))
                    238:        {
                    239:                switch (objectID)
                    240:                {
                    241:                        case ED25519_SUBJECT_PUBLIC_KEY_ALGORITHM:
                    242:                        {
                    243:                                oid = asn1_parse_algorithmIdentifier(object,
                    244:                                                                                parser->get_level(parser) + 1, NULL);
                    245:                                if (oid != OID_ED25519)
                    246:                                {
                    247:                                        goto end;
                    248:                                }
                    249:                                break;
                    250:                        }
                    251:                        case ED25519_SUBJECT_PUBLIC_KEY:
                    252:                        {
                    253:                                /* encoded as an ASN1 BIT STRING */
                    254:                                if (object.len != 1 + ED25519_KEY_LEN)
                    255:                                {
                    256:                                        goto end;
                    257:                                }
                    258:                                this->pubkey = chunk_clone(chunk_skip(object, 1));
                    259:                                break;
                    260:                        }
                    261:                }
                    262:        }
                    263:        success = parser->success(parser);
                    264: 
                    265: end:
                    266:        parser->destroy(parser);
                    267:        return success;
                    268: }
                    269: 
                    270: /**
                    271:  * See header.
                    272:  */
                    273: curve25519_public_key_t *curve25519_public_key_load(key_type_t type,
                    274:                                                                                                        va_list args)
                    275: {
                    276:        private_curve25519_public_key_t *this;
                    277:        chunk_t asn1 = chunk_empty, blob = chunk_empty;
                    278: 
                    279:        while (TRUE)
                    280:        {
                    281:                switch (va_arg(args, builder_part_t))
                    282:                {
                    283:                        case BUILD_BLOB_ASN1_DER:
                    284:                                asn1 = va_arg(args, chunk_t);
                    285:                                continue;
                    286:                        case BUILD_EDDSA_PUB:
                    287:                                blob = va_arg(args, chunk_t);
                    288:                                continue;
                    289:                        case BUILD_END:
                    290:                                break;
                    291:                        default:
                    292:                                return NULL;
                    293:                }
                    294:                break;
                    295:        }
                    296: 
                    297:        INIT(this,
                    298:                .public = {
                    299:                        .key = {
                    300:                                .get_type = _get_type,
                    301:                                .verify = _verify,
                    302:                                .encrypt = _encrypt_,
                    303:                                .equals = public_key_equals,
                    304:                                .get_keysize = _get_keysize,
                    305:                                .get_fingerprint = _get_fingerprint,
                    306:                                .has_fingerprint = public_key_has_fingerprint,
                    307:                                .get_encoding = _get_encoding,
                    308:                                .get_ref = _get_ref,
                    309:                                .destroy = _destroy,
                    310:                        },
                    311:                },
                    312:                .ref = 1,
                    313:        );
                    314: 
                    315:        if (blob.len == ED25519_KEY_LEN)
                    316:        {
                    317:                this->pubkey = chunk_clone(blob);
                    318:        }
                    319:        else if (!asn1.len || !parse_public_key_info(this, asn1))
                    320:        {
                    321:                destroy(this);
                    322:                return NULL;
                    323:        }
                    324:        return &this->public;
                    325: }
                    326: 
                    327: /**
                    328:  * See header.
                    329:  */
                    330: chunk_t curve25519_public_key_info_encode(chunk_t pubkey)
                    331: {
                    332:        return asn1_wrap(ASN1_SEQUENCE, "mm",
                    333:                                        asn1_wrap(ASN1_SEQUENCE, "m",
                    334:                                                asn1_build_known_oid(OID_ED25519)),
                    335:                                        asn1_bitstring("c", pubkey));
                    336: }
                    337: 
                    338: /**
                    339:  * See header.
                    340:  */
                    341: bool curve25519_public_key_fingerprint(chunk_t pubkey,
                    342:                                                                           cred_encoding_type_t type, chunk_t *fp)
                    343: {
                    344:        hasher_t *hasher;
                    345:        chunk_t key;
                    346: 
                    347:        switch (type)
                    348:        {
                    349:                case KEYID_PUBKEY_SHA1:
                    350:                        key = chunk_clone(pubkey);
                    351:                        break;
                    352:                case KEYID_PUBKEY_INFO_SHA1:
                    353:                        key = curve25519_public_key_info_encode(pubkey);
                    354:                        break;
                    355:                default:
                    356:                        return FALSE;
                    357:        }
                    358: 
                    359:        hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
                    360:        if (!hasher || !hasher->allocate_hash(hasher, key, fp))
                    361:        {
                    362:                DBG1(DBG_LIB, "SHA1 hash algorithm not supported, "
                    363:                         "fingerprinting failed");
                    364:                DESTROY_IF(hasher);
                    365:                free(key.ptr);
                    366:                return FALSE;
                    367:        }
                    368:        hasher->destroy(hasher);
                    369:        free(key.ptr);
                    370:        return TRUE;
                    371: }

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