~ubuntu-branches/ubuntu/jaunty/heimdal/jaunty

« back to all changes in this revision

Viewing changes to lib/krb5/pkinit.c

  • Committer: Bazaar Package Importer
  • Author(s): Nick Ellery
  • Date: 2008-11-17 22:25:58 UTC
  • mfrom: (1.1.5 upstream) (2.1.2 lenny)
  • Revision ID: james.westby@ubuntu.com-20081117222558-jd1aj1jth6ycdb0x
Tags: 1.2.dfsg.1-2.1ubuntu1
* Merge from debian unstable, remaining changes (LP: #299345):
  - Change libdb4.2-dev to libdb4.6-dev in build-deps
  - Add netbase to heimdal-kdc depends.
  - Set CPPFLAGS=-DLDAP_DEPRECATED to fix build with OpenLDAP 2.4 on
    64-bit architectures.
* Remove dependency on update-inetd to heimdal-servers and heimdal-kdc,
  as packages should rely on the inet-superserver to provide the
  update-inetd command.
* Drop the addition of -1 to the version of comerr-dev in build depends.

Show diffs side-by-side

added added

removed removed

Lines of Context:
33
33
 
34
34
#include "krb5_locl.h"
35
35
 
36
 
RCSID("$Id: pkinit.c 22433 2008-01-13 14:11:46Z lha $");
 
36
RCSID("$Id: pkinit.c 22990 2008-04-15 15:55:16Z lha $");
37
37
 
38
38
struct krb5_dh_moduli {
39
39
    char *name;
45
45
 
46
46
#ifdef PKINIT
47
47
 
48
 
#include <heim_asn1.h>
49
 
#include <rfc2459_asn1.h>
50
48
#include <cms_asn1.h>
51
49
#include <pkcs8_asn1.h>
52
50
#include <pkcs9_asn1.h>
56
54
 
57
55
#include <der.h>
58
56
 
59
 
#include <hx509.h>
60
 
 
61
 
enum {
62
 
    COMPAT_WIN2K = 1,
63
 
    COMPAT_IETF = 2
64
 
};
65
 
 
66
 
struct krb5_pk_identity {
67
 
    hx509_context hx509ctx;
68
 
    hx509_verify_ctx verify_ctx;
69
 
    hx509_certs certs;
70
 
    hx509_certs anchors;
71
 
    hx509_certs certpool;
72
 
    hx509_revoke_ctx revokectx;
73
 
};
74
 
 
75
57
struct krb5_pk_cert {
76
58
    hx509_cert cert;
77
59
};
82
64
    krb5_data *clientDHNonce;
83
65
    struct krb5_dh_moduli **m;
84
66
    hx509_peer_info peer;
85
 
    int type;
 
67
    enum krb5_pk_type type;
86
68
    unsigned int require_binding:1;
87
69
    unsigned int require_eku:1;
88
70
    unsigned int require_krbtgt_otherName:1;
91
73
};
92
74
 
93
75
static void
94
 
_krb5_pk_copy_error(krb5_context context,
95
 
                    hx509_context hx509ctx,
96
 
                    int hxret,
97
 
                    const char *fmt,
98
 
                    ...)
 
76
pk_copy_error(krb5_context context,
 
77
              hx509_context hx509ctx,
 
78
              int hxret,
 
79
              const char *fmt,
 
80
              ...)
99
81
    __attribute__ ((format (printf, 4, 5)));
100
82
 
101
83
/*
139
121
    return bn;
140
122
}
141
123
 
142
 
 
143
 
static krb5_error_code
144
 
_krb5_pk_create_sign(krb5_context context,
145
 
                     const heim_oid *eContentType,
146
 
                     krb5_data *eContent,
147
 
                     struct krb5_pk_identity *id,
148
 
                     hx509_peer_info peer,
149
 
                     krb5_data *sd_data)
150
 
{
151
 
    hx509_cert cert;
152
 
    hx509_query *q;
 
124
struct certfind {
 
125
    const char *type;
 
126
    const heim_oid *oid;
 
127
};
 
128
 
 
129
/*
 
130
 * Try searchin the key by to use by first looking for for PK-INIT
 
131
 * EKU, then the Microsoft smart card EKU and last, no special EKU at all.
 
132
 */
 
133
 
 
134
static krb5_error_code
 
135
find_cert(krb5_context context, struct krb5_pk_identity *id, 
 
136
          hx509_query *q, hx509_cert *cert)
 
137
{
 
138
    struct certfind cf[3] = { 
 
139
        { "PKINIT EKU" },
 
140
        { "MS EKU" },
 
141
        { "no" }
 
142
    };
 
143
    int i, ret;
 
144
 
 
145
    cf[0].oid = oid_id_pkekuoid();
 
146
    cf[1].oid = oid_id_pkinit_ms_eku();
 
147
    cf[2].oid = NULL;
 
148
 
 
149
    for (i = 0; i < sizeof(cf)/sizeof(cf[0]); i++) {
 
150
        ret = hx509_query_match_eku(q, cf[i].oid);
 
151
        if (ret) {
 
152
            pk_copy_error(context, id->hx509ctx, ret, 
 
153
                                "Failed setting %s OID", cf[i].type);
 
154
            return ret;
 
155
        }
 
156
 
 
157
        ret = hx509_certs_find(id->hx509ctx, id->certs, q, cert);
 
158
        if (ret == 0)
 
159
            break;
 
160
        pk_copy_error(context, id->hx509ctx, ret, 
 
161
                            "Failed cert for finding %s OID", cf[i].type);
 
162
    }
 
163
    return ret;
 
164
}
 
165
 
 
166
 
 
167
static krb5_error_code
 
168
create_signature(krb5_context context,
 
169
                 const heim_oid *eContentType,
 
170
                 krb5_data *eContent,
 
171
                 struct krb5_pk_identity *id,
 
172
                 hx509_peer_info peer,
 
173
                 krb5_data *sd_data)
 
174
{
 
175
    hx509_cert cert = NULL;
 
176
    hx509_query *q = NULL;
153
177
    int ret;
154
178
 
155
179
    ret = hx509_query_alloc(id->hx509ctx, &q);
156
180
    if (ret) {
157
 
        _krb5_pk_copy_error(context, id->hx509ctx, ret, 
 
181
        pk_copy_error(context, id->hx509ctx, ret, 
158
182
                            "Allocate query to find signing certificate");
159
183
        return ret;
160
184
    }
162
186
    hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY);
163
187
    hx509_query_match_option(q, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE);
164
188
 
165
 
    ret = hx509_certs_find(id->hx509ctx, id->certs, q, &cert);
 
189
    ret = find_cert(context, id, q, &cert);
166
190
    hx509_query_free(id->hx509ctx, q);
167
 
    if (ret) {
168
 
        _krb5_pk_copy_error(context, id->hx509ctx, ret, 
169
 
                            "Find certificate to signed CMS data");
 
191
    if (ret)
170
192
        return ret;
171
 
    }
172
193
 
173
194
    ret = hx509_cms_create_signed_1(id->hx509ctx,
174
195
                                    0,
181
202
                                    NULL,
182
203
                                    id->certs,
183
204
                                    sd_data);
184
 
    if (ret)
185
 
        _krb5_pk_copy_error(context, id->hx509ctx, ret, "create CMS signedData");
186
205
    hx509_cert_free(cert);
 
206
    if (ret) {
 
207
        pk_copy_error(context, id->hx509ctx, ret,
 
208
                            "Create CMS signedData");
 
209
        return ret;
 
210
    }
187
211
 
188
 
    return ret;
 
212
    return 0;
189
213
}
190
214
 
191
215
static int
482
506
    krb5_data_zero(&sd_buf);
483
507
    memset(&content_info, 0, sizeof(content_info));
484
508
 
485
 
    if (ctx->type == COMPAT_WIN2K) {
 
509
    if (ctx->type == PKINIT_WIN2K) {
486
510
        AuthPack_Win2k ap;
487
511
        krb5_timestamp sec;
488
512
        int32_t usec;
512
536
                           &ap, &size, ret);
513
537
        free_AuthPack_Win2k(&ap);
514
538
        if (ret) {
515
 
            krb5_set_error_string(context, "AuthPack_Win2k: %d", ret);
 
539
            krb5_set_error_string(context, "AuthPack_Win2k: %d", 
 
540
                                  (int)ret);
516
541
            goto out;
517
542
        }
518
543
        if (buf.length != size)
519
544
            krb5_abortx(context, "internal ASN1 encoder error");
520
545
 
521
546
        oid = oid_id_pkcs7_data();
522
 
    } else if (ctx->type == COMPAT_IETF) {
 
547
    } else if (ctx->type == PKINIT_27) {
523
548
        AuthPack ap;
524
549
        
525
550
        memset(&ap, 0, sizeof(ap));
533
558
        ASN1_MALLOC_ENCODE(AuthPack, buf.data, buf.length, &ap, &size, ret);
534
559
        free_AuthPack(&ap);
535
560
        if (ret) {
536
 
            krb5_set_error_string(context, "AuthPack: %d", ret);
 
561
            krb5_set_error_string(context, "AuthPack: %d", (int)ret);
537
562
            goto out;
538
563
        }
539
564
        if (buf.length != size)
543
568
    } else
544
569
        krb5_abortx(context, "internal pkinit error");
545
570
 
546
 
    ret = _krb5_pk_create_sign(context,
547
 
                               oid,
548
 
                               &buf,
549
 
                               ctx->id,
550
 
                               ctx->peer,
551
 
                               &sd_buf);
 
571
    ret = create_signature(context, oid, &buf, ctx->id,
 
572
                           ctx->peer, &sd_buf);
552
573
    krb5_data_free(&buf);
553
574
    if (ret)
554
575
        goto out;
561
582
        goto out;
562
583
    }
563
584
 
564
 
    if (ctx->type == COMPAT_WIN2K) {
 
585
    if (ctx->type == PKINIT_WIN2K) {
565
586
        PA_PK_AS_REQ_Win2k winreq;
566
587
 
567
588
        pa_type = KRB5_PADATA_PK_AS_REQ_WIN;
574
595
                           &winreq, &size, ret);
575
596
        free_PA_PK_AS_REQ_Win2k(&winreq);
576
597
 
577
 
    } else if (ctx->type == COMPAT_IETF) {
 
598
    } else if (ctx->type == PKINIT_27) {
578
599
        PA_PK_AS_REQ req;
579
600
 
580
601
        pa_type = KRB5_PADATA_PK_AS_REQ;
608
629
    } else
609
630
        krb5_abortx(context, "internal pkinit error");
610
631
    if (ret) {
611
 
        krb5_set_error_string(context, "PA-PK-AS-REQ %d", ret);
 
632
        krb5_set_error_string(context, "PA-PK-AS-REQ %d", (int)ret);
612
633
        goto out;
613
634
    }
614
635
    if (buf.length != size)
618
639
    if (ret)
619
640
        free(buf.data);
620
641
 
621
 
    if (ret == 0 && ctx->type == COMPAT_WIN2K)
 
642
    if (ret == 0 && ctx->type == PKINIT_WIN2K)
622
643
        krb5_padata_add(context, md, KRB5_PADATA_PK_AS_09_BINDING, NULL, 0);
623
644
 
624
645
out:
653
674
                                         req_body->realm,
654
675
                                         "pkinit_win2k_require_binding",
655
676
                                         NULL);
656
 
        ctx->type = COMPAT_WIN2K;
 
677
        ctx->type = PKINIT_WIN2K;
657
678
    } else
658
 
        ctx->type = COMPAT_IETF;
 
679
        ctx->type = PKINIT_27;
659
680
 
660
681
    ctx->require_eku = 
661
682
        krb5_config_get_bool_default(context, NULL,
715
736
                                  content,
716
737
                                  &signer_certs);
717
738
    if (ret) {
718
 
        _krb5_pk_copy_error(context, id->hx509ctx, ret,
 
739
        pk_copy_error(context, id->hx509ctx, ret,
719
740
                            "CMS verify signed failed");
720
741
        return ret;
721
742
    }
729
750
        
730
751
    ret = hx509_get_one_cert(id->hx509ctx, signer_certs, &(*signer)->cert);
731
752
    if (ret) {
732
 
        _krb5_pk_copy_error(context, id->hx509ctx, ret,
 
753
        pk_copy_error(context, id->hx509ctx, ret,
733
754
                            "Failed to get on of the signer certs");
734
755
        goto out;
735
756
    }
968
989
                               &contentType,
969
990
                               &content);
970
991
    if (ret) {
971
 
        _krb5_pk_copy_error(context, ctx->id->hx509ctx, ret,
 
992
        pk_copy_error(context, ctx->id->hx509ctx, ret,
972
993
                            "Failed to unenvelope CMS data in PK-INIT reply");
973
994
        return ret;
974
995
    }
993
1014
#endif
994
1015
 
995
1016
    /* win2k uses ContentInfo */
996
 
    if (type == COMPAT_WIN2K) {
 
1017
    if (type == PKINIT_WIN2K) {
997
1018
        heim_oid type;
998
1019
        heim_octet_string out;
999
1020
 
1032
1053
    }
1033
1054
 
1034
1055
#if 0
1035
 
    if (type == COMPAT_WIN2K) {
 
1056
    if (type == PKINIT_WIN2K) {
1036
1057
        if (der_heim_oid_cmp(&contentType, oid_id_pkcs7_data()) != 0) {
1037
1058
            krb5_set_error_string(context, "PKINIT: reply key, wrong oid");
1038
1059
            ret = KRB5KRB_AP_ERR_MSG_TYPE;
1048
1069
#endif
1049
1070
 
1050
1071
    switch(type) {
1051
 
    case COMPAT_WIN2K:
 
1072
    case PKINIT_WIN2K:
1052
1073
        ret = get_reply_key(context, &content, req_buffer, key);
1053
1074
        if (ret != 0 && ctx->require_binding == 0)
1054
1075
            ret = get_reply_key_win(context, &content, nonce, key);
1055
1076
        break;
1056
 
    case COMPAT_IETF:
 
1077
    case PKINIT_27:
1057
1078
        ret = get_reply_key(context, &content, req_buffer, key);
1058
1079
        break;
1059
1080
    }
1260
1281
    size_t size;
1261
1282
 
1262
1283
    /* Check for IETF PK-INIT first */
1263
 
    if (ctx->type == COMPAT_IETF) {
 
1284
    if (ctx->type == PKINIT_27) {
1264
1285
        PA_PK_AS_REP rep;
1265
1286
        heim_octet_string os, data;
1266
1287
        heim_oid oid;
1308
1329
                                    nonce, pa, key);
1309
1330
            break;
1310
1331
        case choice_PA_PK_AS_REP_encKeyPack:
1311
 
            ret = pk_rd_pa_reply_enckey(context, COMPAT_IETF, &data, &oid, realm, 
 
1332
            ret = pk_rd_pa_reply_enckey(context, PKINIT_27, &data, &oid, realm, 
1312
1333
                                        ctx, etype, hi, nonce, req_buffer, pa, key);
1313
1334
            break;
1314
1335
        default:
1318
1339
        der_free_oid(&oid);
1319
1340
        free_PA_PK_AS_REP(&rep);
1320
1341
 
1321
 
    } else if (ctx->type == COMPAT_WIN2K) {
 
1342
    } else if (ctx->type == PKINIT_WIN2K) {
1322
1343
        PA_PK_AS_REP_Win2k w2krep;
1323
1344
 
1324
1345
        /* Check for Windows encoding of the AS-REP pa data */ 
1338
1359
                                        &size);
1339
1360
        if (ret) {
1340
1361
            krb5_set_error_string(context, "PKINIT: Failed decoding windows "
1341
 
                                  "pkinit reply %d", ret);
 
1362
                                  "pkinit reply %d", (int)ret);
1342
1363
            return ret;
1343
1364
        }
1344
1365
 
1357
1378
                return ret;
1358
1379
            }
1359
1380
 
1360
 
            ret = pk_rd_pa_reply_enckey(context, COMPAT_WIN2K, &data, &oid, realm,
 
1381
            ret = pk_rd_pa_reply_enckey(context, PKINIT_WIN2K, &data, &oid, realm,
1361
1382
                                        ctx, etype, hi, nonce, req_buffer, pa, key);
1362
1383
            der_free_octet_string(&data);
1363
1384
            der_free_oid(&oid);
1486
1507
 
1487
1508
    ret = hx509_certs_init(id->hx509ctx, user_id, 0, lock, &id->certs);
1488
1509
    if (ret) {
1489
 
        _krb5_pk_copy_error(context, id->hx509ctx, ret,
 
1510
        pk_copy_error(context, id->hx509ctx, ret,
1490
1511
                            "Failed to init cert certs");
1491
1512
        goto out;
1492
1513
    }
1493
1514
 
1494
1515
    ret = hx509_certs_init(id->hx509ctx, anchor_id, 0, NULL, &id->anchors);
1495
1516
    if (ret) {
1496
 
        _krb5_pk_copy_error(context, id->hx509ctx, ret,
 
1517
        pk_copy_error(context, id->hx509ctx, ret,
1497
1518
                            "Failed to init anchors");
1498
1519
        goto out;
1499
1520
    }
1501
1522
    ret = hx509_certs_init(id->hx509ctx, "MEMORY:pkinit-cert-chain", 
1502
1523
                           0, NULL, &id->certpool);
1503
1524
    if (ret) {
1504
 
        _krb5_pk_copy_error(context, id->hx509ctx, ret,
 
1525
        pk_copy_error(context, id->hx509ctx, ret,
1505
1526
                            "Failed to init chain");
1506
1527
        goto out;
1507
1528
    }
1510
1531
        ret = hx509_certs_append(id->hx509ctx, id->certpool,
1511
1532
                                 NULL, *chain_list);
1512
1533
        if (ret) {
1513
 
            _krb5_pk_copy_error(context, id->hx509ctx, ret,
 
1534
            pk_copy_error(context, id->hx509ctx, ret,
1514
1535
                                "Failed to laod chain %s",
1515
1536
                                *chain_list);
1516
1537
            goto out;
1521
1542
    if (revoke_list) {
1522
1543
        ret = hx509_revoke_init(id->hx509ctx, &id->revokectx);
1523
1544
        if (ret) {
1524
 
            _krb5_pk_copy_error(context, id->hx509ctx, ret,
 
1545
            pk_copy_error(context, id->hx509ctx, ret,
1525
1546
                                "Failed init revoke list");
1526
1547
            goto out;
1527
1548
        }
1531
1552
                                       id->revokectx,
1532
1553
                                       *revoke_list);
1533
1554
            if (ret) {
1534
 
                _krb5_pk_copy_error(context, id->hx509ctx, ret, 
 
1555
                pk_copy_error(context, id->hx509ctx, ret, 
1535
1556
                                    "Failed load revoke list");
1536
1557
                goto out;
1537
1558
            }
1542
1563
 
1543
1564
    ret = hx509_verify_init_ctx(id->hx509ctx, &id->verify_ctx);
1544
1565
    if (ret) {
1545
 
        _krb5_pk_copy_error(context, id->hx509ctx, ret, 
 
1566
        pk_copy_error(context, id->hx509ctx, ret, 
1546
1567
                            "Failed init verify context");
1547
1568
        goto out;
1548
1569
    }
1606
1627
    return 0;
1607
1628
}
1608
1629
 
 
1630
/*
 
1631
 *
 
1632
 */
 
1633
 
 
1634
static void
 
1635
pk_copy_error(krb5_context context,
 
1636
              hx509_context hx509ctx,
 
1637
              int hxret,
 
1638
              const char *fmt,
 
1639
              ...)
 
1640
{
 
1641
    va_list va;
 
1642
    char *s, *f;
 
1643
 
 
1644
    va_start(va, fmt);
 
1645
    vasprintf(&f, fmt, va);
 
1646
    va_end(va);
 
1647
    if (f == NULL) {
 
1648
        krb5_clear_error_string(context);
 
1649
        return;
 
1650
    }
 
1651
 
 
1652
    s = hx509_get_error_string(hx509ctx, hxret);
 
1653
    if (s == NULL) {
 
1654
        krb5_clear_error_string(context);
 
1655
        free(f);
 
1656
        return;
 
1657
    }
 
1658
    krb5_set_error_string(context, "%s: %s", f, s);
 
1659
    free(s);
 
1660
    free(f);
 
1661
}
 
1662
 
1609
1663
#endif /* PKINIT */
1610
1664
 
1611
1665
static int
2035
2089
    return EINVAL;
2036
2090
#endif
2037
2091
}
2038
 
 
2039
 
/*
2040
 
 *
2041
 
 */
2042
 
 
2043
 
static void
2044
 
_krb5_pk_copy_error(krb5_context context,
2045
 
                    hx509_context hx509ctx,
2046
 
                    int hxret,
2047
 
                    const char *fmt,
2048
 
                    ...)
2049
 
{
2050
 
    va_list va;
2051
 
    char *s, *f;
2052
 
 
2053
 
    va_start(va, fmt);
2054
 
    vasprintf(&f, fmt, va);
2055
 
    va_end(va);
2056
 
    if (f == NULL) {
2057
 
        krb5_clear_error_string(context);
2058
 
        return;
2059
 
    }
2060
 
 
2061
 
    s = hx509_get_error_string(hx509ctx, hxret);
2062
 
    if (s == NULL) {
2063
 
        krb5_clear_error_string(context);
2064
 
        free(f);
2065
 
        return;
2066
 
    }
2067
 
    krb5_set_error_string(context, "%s: %s", f, s);
2068
 
    free(s);
2069
 
    free(f);
2070
 
}