Annotation of embedaddon/strongswan/src/libstrongswan/plugins/pgp/pgp_cert.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * Copyright (C) 2009 Martin Willi
                      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: #include "pgp_cert.h"
                     17: #include "pgp_utils.h"
                     18: 
                     19: #include <time.h>
                     20: 
                     21: #include <utils/debug.h>
                     22: 
                     23: typedef struct private_pgp_cert_t private_pgp_cert_t;
                     24: 
                     25: /**
                     26:  * Private data of an pgp_cert_t object.
                     27:  */
                     28: struct private_pgp_cert_t {
                     29: 
                     30:        /**
                     31:         * Implements pgp_cert_t interface.
                     32:         */
                     33:        pgp_cert_t public;
                     34: 
                     35:        /**
                     36:         * Public key of the certificate
                     37:         */
                     38:        public_key_t *key;
                     39: 
                     40:        /**
                     41:         * version of the public key
                     42:         */
                     43:        uint32_t version;
                     44: 
                     45:        /**
                     46:         * creation time
                     47:         */
                     48:        uint32_t created;
                     49: 
                     50:        /**
                     51:         * days the certificate is valid
                     52:         */
                     53:        uint32_t valid;
                     54: 
                     55:        /**
                     56:         * userid of the certificate
                     57:         */
                     58:        identification_t *user_id;
                     59: 
                     60:        /**
                     61:         * v3 or v4 fingerprint of the PGP public key
                     62:         */
                     63:        chunk_t fingerprint;
                     64: 
                     65:        /**
                     66:         * full PGP encoding
                     67:         */
                     68:        chunk_t encoding;
                     69: 
                     70:        /**
                     71:         * reference counter
                     72:         */
                     73:        refcount_t ref;
                     74: };
                     75: 
                     76: 
                     77: METHOD(certificate_t, get_type, certificate_type_t,
                     78:        private_pgp_cert_t *this)
                     79: {
                     80:        return CERT_GPG;
                     81: }
                     82: 
                     83: METHOD(certificate_t, get_subject,identification_t*,
                     84:        private_pgp_cert_t *this)
                     85: {
                     86:        return this->user_id;
                     87: }
                     88: 
                     89: METHOD(certificate_t, get_issuer, identification_t*,
                     90:        private_pgp_cert_t *this)
                     91: {
                     92:        return this->user_id;
                     93: }
                     94: 
                     95: METHOD(certificate_t, has_subject, id_match_t,
                     96:        private_pgp_cert_t *this, identification_t *subject)
                     97: {
                     98:        id_match_t match_user_id;
                     99: 
                    100:        match_user_id = this->user_id->matches(this->user_id, subject);
                    101:        if (match_user_id == ID_MATCH_NONE &&
                    102:                subject->get_type(subject) == ID_KEY_ID &&
                    103:         chunk_equals(this->fingerprint, subject->get_encoding(subject)))
                    104:        {
                    105:                return ID_MATCH_PERFECT;
                    106:        }
                    107:        return match_user_id;
                    108: }
                    109: 
                    110: METHOD(certificate_t, has_issuer, id_match_t,
                    111:        private_pgp_cert_t *this, identification_t *issuer)
                    112: {
                    113:        return ID_MATCH_NONE;
                    114: }
                    115: 
                    116: METHOD(certificate_t, issued_by,bool,
                    117:        private_pgp_cert_t *this, certificate_t *issuer, signature_params_t **scheme)
                    118: {
                    119:        /* TODO: check signature blobs for a valid signature */
                    120:        return FALSE;
                    121: }
                    122: 
                    123: METHOD(certificate_t, get_public_key, public_key_t*,
                    124:        private_pgp_cert_t *this)
                    125: {
                    126:        this->key->get_ref(this->key);
                    127:        return this->key;
                    128: }
                    129: 
                    130: METHOD(certificate_t, get_ref, certificate_t*,
                    131:        private_pgp_cert_t *this)
                    132: {
                    133:        ref_get(&this->ref);
                    134:        return &this->public.interface.interface;
                    135: }
                    136: 
                    137: METHOD(certificate_t, get_validity, bool,
                    138:        private_pgp_cert_t *this, time_t *when, time_t *not_before,
                    139:        time_t *not_after)
                    140: {
                    141:        time_t t, until;
                    142: 
                    143:        if (when)
                    144:        {
                    145:                t = *when;
                    146:        }
                    147:        else
                    148:        {
                    149:                t = time(NULL);
                    150:        }
                    151:        if (not_before)
                    152:        {
                    153:                *not_before = this->created;
                    154:        }
                    155:        if (this->valid)
                    156:        {
                    157:                until = this->valid + this->created * 24 * 60 * 60;
                    158:        }
                    159:        else
                    160:        {
                    161:                /* Jan 19 03:14:07 UTC 2038 */
                    162:                until = TIME_32_BIT_SIGNED_MAX;
                    163:        }
                    164:        if (not_after)
                    165:        {
                    166:                *not_after = until;
                    167:        }
                    168:        return (t >= this->valid && t <= until);
                    169: }
                    170: 
                    171: METHOD(certificate_t, get_encoding, bool,
                    172:        private_pgp_cert_t *this, cred_encoding_type_t type, chunk_t *encoding)
                    173: {
                    174:        if (type == CERT_PGP_PKT)
                    175:        {
                    176:                *encoding = chunk_clone(this->encoding);
                    177:                return TRUE;
                    178:        }
                    179:        return lib->encoding->encode(lib->encoding, type, NULL, encoding,
                    180:                                                CRED_PART_PGP_CERT, this->encoding, CRED_PART_END);
                    181: }
                    182: 
                    183: METHOD(certificate_t, equals, bool,
                    184:        private_pgp_cert_t *this, certificate_t *other)
                    185: {
                    186:        chunk_t encoding;
                    187:        bool equal;
                    188: 
                    189:        if (this == (private_pgp_cert_t*)other)
                    190:        {
                    191:                return TRUE;
                    192:        }
                    193:        if (other->get_type(other) != CERT_X509)
                    194:        {
                    195:                return FALSE;
                    196:        }
                    197:        if (other->equals == (void*)equals)
                    198:        {       /* skip allocation if we have the same implementation */
                    199:                return chunk_equals(this->encoding, ((private_pgp_cert_t*)other)->encoding);
                    200:        }
                    201:        if (!other->get_encoding(other, CERT_PGP_PKT, &encoding))
                    202:        {
                    203:                return FALSE;
                    204:        }
                    205:        equal = chunk_equals(this->encoding, encoding);
                    206:        free(encoding.ptr);
                    207:        return equal;
                    208: }
                    209: 
                    210: METHOD(certificate_t, destroy, void,
                    211:        private_pgp_cert_t *this)
                    212: {
                    213:        if (ref_put(&this->ref))
                    214:        {
                    215:                DESTROY_IF(this->key);
                    216:                DESTROY_IF(this->user_id);
                    217:                free(this->fingerprint.ptr);
                    218:                free(this->encoding.ptr);
                    219:                free(this);
                    220:        }
                    221: }
                    222: 
                    223: METHOD(pgp_certificate_t, get_fingerprint, chunk_t,
                    224:        private_pgp_cert_t *this)
                    225: {
                    226:        return this->fingerprint;
                    227: }
                    228: 
                    229: /**
                    230:  * See header
                    231:  */
                    232: private_pgp_cert_t *create_empty()
                    233: {
                    234:        private_pgp_cert_t *this;
                    235: 
                    236:        INIT(this,
                    237:                .public = {
                    238:                        .interface = {
                    239:                                .interface = {
                    240:                                        .get_type = _get_type,
                    241:                                        .get_subject = _get_subject,
                    242:                                        .get_issuer = _get_issuer,
                    243:                                        .has_subject = _has_subject,
                    244:                                        .has_issuer = _has_issuer,
                    245:                                        .issued_by = _issued_by,
                    246:                                        .get_public_key = _get_public_key,
                    247:                                        .get_validity = _get_validity,
                    248:                                        .get_encoding = _get_encoding,
                    249:                                        .equals = _equals,
                    250:                                        .get_ref = _get_ref,
                    251:                                        .destroy = _destroy,
                    252:                                },
                    253:                                .get_fingerprint = _get_fingerprint,
                    254:                        },
                    255:                },
                    256:                .ref = 1,
                    257:        );
                    258: 
                    259:        return this;
                    260: }
                    261: 
                    262: /**
                    263:  * Parse the public key packet of a PGP certificate
                    264:  */
                    265: static bool parse_public_key(private_pgp_cert_t *this, chunk_t packet)
                    266: {
                    267:        chunk_t pubkey_packet = packet;
                    268: 
                    269:        if (!pgp_read_scalar(&packet, 1, &this->version))
                    270:        {
                    271:                return FALSE;
                    272:        }
                    273:        switch (this->version)
                    274:        {
                    275:                case 3:
                    276:                        if (!pgp_read_scalar(&packet, 4, &this->created) ||
                    277:                                !pgp_read_scalar(&packet, 2, &this->valid))
                    278:                        {
                    279:                                return FALSE;
                    280:                        }
                    281:                        break;
                    282:                case 4:
                    283:                        if (!pgp_read_scalar(&packet, 4, &this->created))
                    284:                        {
                    285:                                return FALSE;
                    286:                        }
                    287:                        break;
                    288:                default:
                    289:                        DBG1(DBG_ASN, "PGP packet version V%d not supported",
                    290:                                 this->version);
                    291:                        return FALSE;
                    292:        }
                    293:        if (this->valid)
                    294:        {
                    295:                DBG2(DBG_ASN, "L2 - created %T, valid %d days", &this->created, FALSE,
                    296:                         this->valid);
                    297:        }
                    298:        else
                    299:        {
                    300:                DBG2(DBG_ASN, "L2 - created %T, never expires", &this->created, FALSE);
                    301:        }
                    302:        DESTROY_IF(this->key);
                    303:        this->key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ANY,
                    304:                                                                        BUILD_BLOB_PGP, packet, BUILD_END);
                    305:        if (this->key == NULL)
                    306:        {
                    307:                return FALSE;
                    308:        }
                    309: 
                    310:        /* compute V4 or V3 fingerprint according to section 12.2 of RFC 4880 */
                    311:        if (this->version == 4)
                    312:        {
                    313:                chunk_t pubkey_packet_header = chunk_from_chars(
                    314:                                        0x99, pubkey_packet.len / 256, pubkey_packet.len % 256
                    315:                                );
                    316:                hasher_t *hasher;
                    317: 
                    318:                hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
                    319:                if (hasher == NULL)
                    320:                {
                    321:                        DBG1(DBG_ASN, "no SHA-1 hasher available");
                    322:                        return FALSE;
                    323:                }
                    324:                if (!hasher->allocate_hash(hasher, pubkey_packet_header, NULL) ||
                    325:                        !hasher->allocate_hash(hasher, pubkey_packet, &this->fingerprint))
                    326:                {
                    327:                        hasher->destroy(hasher);
                    328:                        return FALSE;
                    329:                }
                    330:                hasher->destroy(hasher);
                    331:                DBG2(DBG_ASN, "L2 - v4 fingerprint %#B", &this->fingerprint);
                    332:        }
                    333:        else
                    334:        {
                    335:                /* V3 fingerprint is computed by public_key_t class */
                    336:                if (!this->key->get_fingerprint(this->key, KEYID_PGPV3,
                    337:                                                                                &this->fingerprint))
                    338:                {
                    339:                        return FALSE;
                    340:                }
                    341:                this->fingerprint = chunk_clone(this->fingerprint);
                    342:                DBG2(DBG_ASN, "L2 - v3 fingerprint %#B", &this->fingerprint);
                    343:        }
                    344:        return TRUE;
                    345: }
                    346: 
                    347: /**
                    348:  * Parse the signature packet of a PGP certificate
                    349:  */
                    350: static bool parse_signature(private_pgp_cert_t *this, chunk_t packet)
                    351: {
                    352:        uint32_t version, len, type, created;
                    353: 
                    354:        if (!pgp_read_scalar(&packet, 1, &version))
                    355:        {
                    356:                return FALSE;
                    357:        }
                    358: 
                    359:        /* we parse only v3 or v4 signature packets */
                    360:        if (version != 3 && version != 4)
                    361:        {
                    362:                DBG2(DBG_ASN, "L2 - v%d signature ignored", version);
                    363:                return TRUE;
                    364:        }
                    365:        if (version == 4)
                    366:        {
                    367:                if (!pgp_read_scalar(&packet, 1, &type))
                    368:                {
                    369:                        return FALSE;
                    370:                }
                    371:                DBG2(DBG_ASN, "L2 - v%d signature of type 0x%02x", version, type);
                    372:        }
                    373:        else
                    374:        {
                    375:                if (!pgp_read_scalar(&packet, 1, &len) || len != 5)
                    376:                {
                    377:                        return FALSE;
                    378:                }
                    379:                if (!pgp_read_scalar(&packet, 1, &type) ||
                    380:                        !pgp_read_scalar(&packet, 4, &created))
                    381:                {
                    382:                        return FALSE;
                    383:                }
                    384:                DBG2(DBG_ASN, "L2 - v3 signature of type 0x%02x, created %T", type,
                    385:                         &created, FALSE);
                    386:        }
                    387:        /* TODO: parse and save signature to a list */
                    388:        return TRUE;
                    389: }
                    390: 
                    391: /**
                    392:  * Parse the userid packet of a PGP certificate
                    393:  */
                    394: static bool parse_user_id(private_pgp_cert_t *this, chunk_t packet)
                    395: {
                    396:        DESTROY_IF(this->user_id);
                    397:        this->user_id = identification_create_from_encoding(ID_KEY_ID, packet);
                    398:        DBG2(DBG_ASN, "L2 - '%Y'", this->user_id);
                    399:        return TRUE;
                    400: }
                    401: 
                    402: /**
                    403:  * See header.
                    404:  */
                    405: pgp_cert_t *pgp_cert_load(certificate_type_t type, va_list args)
                    406: {
                    407:        chunk_t packet, blob = chunk_empty;
                    408:        pgp_packet_tag_t tag;
                    409:        private_pgp_cert_t *this;
                    410: 
                    411:        while (TRUE)
                    412:        {
                    413:                switch (va_arg(args, builder_part_t))
                    414:                {
                    415:                        case BUILD_BLOB_PGP:
                    416:                                blob = va_arg(args, chunk_t);
                    417:                                continue;
                    418:                        case BUILD_END:
                    419:                                break;
                    420:                        default:
                    421:                                return NULL;
                    422:                }
                    423:                break;
                    424:        }
                    425: 
                    426:        this = create_empty();
                    427:        this->encoding = chunk_clone(blob);
                    428:        while (blob.len)
                    429:        {
                    430:                if (!pgp_read_packet(&blob, &packet, &tag))
                    431:                {
                    432:                        destroy(this);
                    433:                        return NULL;
                    434:                }
                    435:                switch (tag)
                    436:                {
                    437:                        case PGP_PKT_PUBLIC_KEY:
                    438:                                if (!parse_public_key(this, packet))
                    439:                                {
                    440:                                        destroy(this);
                    441:                                        return NULL;
                    442:                                }
                    443:                                break;
                    444:                        case PGP_PKT_SIGNATURE:
                    445:                                if (!parse_signature(this, packet))
                    446:                                {
                    447:                                        destroy(this);
                    448:                                        return NULL;
                    449:                                }
                    450:                                break;
                    451:                        case PGP_PKT_USER_ID:
                    452:                                if (!parse_user_id(this, packet))
                    453:                                {
                    454:                                        destroy(this);
                    455:                                        return NULL;
                    456:                                }
                    457:                                break;
                    458:                        default:
                    459:                                DBG1(DBG_LIB, "ignoring %N packet in PGP certificate",
                    460:                                         pgp_packet_tag_names, tag);
                    461:                                break;
                    462:                }
                    463:        }
                    464:        if (this->key)
                    465:        {
                    466:                return &this->public;
                    467:        }
                    468:        destroy(this);
                    469:        return NULL;
                    470: }
                    471: 

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