qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

crypto-tls-x509-helpers.c (16625B)


      1 /*
      2  * Copyright (C) 2015 Red Hat, Inc.
      3  *
      4  * This library is free software; you can redistribute it and/or
      5  * modify it under the terms of the GNU Lesser General Public
      6  * License as published by the Free Software Foundation; either
      7  * version 2.1 of the License, or (at your option) any later version.
      8  *
      9  * This library is distributed in the hope that it will be useful,
     10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     12  * Lesser General Public License for more details.
     13  *
     14  * You should have received a copy of the GNU Lesser General Public
     15  * License along with this library.  If not, see
     16  * <http://www.gnu.org/licenses/>.
     17  *
     18  * Author: Daniel P. Berrange <berrange@redhat.com>
     19  */
     20 
     21 #include "qemu/osdep.h"
     22 
     23 #include "crypto-tls-x509-helpers.h"
     24 #include "crypto/init.h"
     25 #include "qemu/sockets.h"
     26 
     27 /*
     28  * This stores some static data that is needed when
     29  * encoding extensions in the x509 certs
     30  */
     31 asn1_node pkix_asn1;
     32 
     33 /*
     34  * To avoid consuming random entropy to generate keys,
     35  * here's one we prepared earlier :-)
     36  */
     37 gnutls_x509_privkey_t privkey;
     38 # define PRIVATE_KEY \
     39     "-----BEGIN RSA PRIVATE KEY-----\n" \
     40     "MIIG5AIBAAKCAYEAyjWyLSNm5PZvYUKUcDWGqbLX10b2ood+YaFjWSnJrqx/q3qh\n" \
     41     "rVGBJglD25AJENJsmZF3zPP1oMhfIxsXu63Hdkb6Rdlc2RUoUP34x9VC1izH25mR\n" \
     42     "6c8DPDp1d6IraZ/llDMI1HsBFz0qGWtvOHgm815XG4PAr/N8rDsuqfv/cJ01KlnO\n" \
     43     "0OdO5QRXCJf9g/dYd41MPu7wOXk9FqjQlmRoP59HgtJ+zUpE4z+Keruw9cMT9VJj\n" \
     44     "0oT+pQ9ysenqeZ3gbT224T1khrEhT5kifhtFLNyDssRchUUWH0hiqoOO1vgb+850\n" \
     45     "W6/1VdxvuPam48py4diSPi1Vip8NITCOBaX9FIpVp4Ruw4rTPVMNMjq9Cpx/DwMP\n" \
     46     "9MbfXfnaVaZaMrmq67/zPhl0eVbUrecH2hQ3ZB9oIF4GkNskzlWF5+yPy6zqk304\n" \
     47     "AKaiFR6jRyh3YfHo2XFqV8x/hxdsIEXOtEUGhSIcpynsW+ckUCartzu7xbhXjd4b\n" \
     48     "kxJT89+riPFYij09AgMBAAECggGBAKyFkaZXXROeejrmHlV6JZGlp+fhgM38gkRz\n" \
     49     "+Jp7P7rLLAY3E7gXIPQ91WqAAmwazFNdvHPd9USfkCQYmnAi/VoZhrCPmlsQZRxt\n" \
     50     "A5QjjOnEvSPMa6SrXZxGWDCg6R8uMCb4P+FhrPWR1thnRDZOtRTQ+crc50p3mHgt\n" \
     51     "6ktXWIJRbqnag8zSfQqCYGtRmhe8sfsWT+Yl4El4+jjaAVU/B364u7+PLmaiphGp\n" \
     52     "BdJfTsTwEpgtGkPj+osDmhzXcZkfq3V+fz5JLkemsCiQKmn4VJRpg8c3ZmE8NPNt\n" \
     53     "gRtGWZ4W3WKDvhotT65WpQx4+6R8Duux/blNPBmH1Upmwd7kj7GYFBArbCjgd9PT\n" \
     54     "xgfCSUZpgOZHHkcgSB+022a8XncXna7WYYij28SLtwImFyu0nNtqECFQHH5u+k6C\n" \
     55     "LRYBSN+3t3At8dQuk01NVrJBndmjmXRfxpqUtTdeaNgVpdUYRY98s30G68NYGSra\n" \
     56     "aEvhhRSghkcLNetkobpY9pUgeqW/tQKBwQDZHHK9nDMt/zk1TxtILeUSitPXcv1/\n" \
     57     "8ufXqO0miHdH23XuXhIEA6Ef26RRVGDGgpjkveDJK/1w5feJ4H/ni4Vclil/cm38\n" \
     58     "OwRqjjd7ElHJX6JQbsxEx/gNTk5/QW1iAL9TXUalgepsSXYT6AJ0/CJv0jmJSJ36\n" \
     59     "YoKMOM8uqzb2KhN6i+RlJRi5iY53kUhWTJq5ArWvNhUzQNSYODI4bNxlsKSBL2Ik\n" \
     60     "LZ5QKHuaEjQet0IlPlfIb4PzMm8CHa/urOcCgcEA7m3zW/lL5bIFoKPjWig5Lbn1\n" \
     61     "aHfrG2ngqzWtgWtfZqMH8OkZc1Mdhhmvd46titjiLjeI+UP/uHXR0068PnrNngzl\n" \
     62     "tTgwlakzu+bWzqhBm1F+3/341st/FEk07r0P/3/PhezVjwfO8c8Exj7pLxH4wrH0\n" \
     63     "ROHgDbClmlJRu6OO78wk1+Vapf5DWa8YfA+q+fdvr7KvgGyytheKMT/b/dsqOq7y\n" \
     64     "qZPjmaJKWAvV3RWG8lWHFSdHx2IAHMHfGr17Y/w7AoHBALzwZeYebeekiVucGSjq\n" \
     65     "T8SgLhT7zCIx+JMUPjVfYzaUhP/Iu7Lkma6IzWm9nW6Drpy5pUpMzwUWDCLfzU9q\n" \
     66     "eseFIl337kEn9wLn+t5OpgAyCqYmlftxbqvdrrBN9uvnrJjWvqk/8wsDrw9JxAGc\n" \
     67     "fjeD4nBXUqvYWLXApoR9mZoGKedmoH9pFig4zlO9ig8YITnKYuQ0k6SD0b8agJHc\n" \
     68     "Ir0YSUDnRGgpjvFBGbeOCe+FGbohk/EpItJc3IAh5740lwKBwAdXd2DjokSmYKn7\n" \
     69     "oeqKxofz6+yVlLW5YuOiuX78sWlVp87xPolgi84vSEnkKM/Xsc8+goc6YstpRVa+\n" \
     70     "W+mImoA9YW1dF5HkLeWhTAf9AlgoAEIhbeIfTgBv6KNZSv7RDrDPBBxtXx/vAfSg\n" \
     71     "x0ldwk0scZsVYXLKd67yzfV7KdGUdaX4N/xYgfZm/9gCG3+q8NN2KxVHQ5F71BOE\n" \
     72     "JeABOaGo9WvnU+DNMIDZjHJMUWVw4MHz/a/UArDf/2CxaPVBNQKBwASg6j4ohSTk\n" \
     73     "J7aE6RQ3OBmmDDpixcoCJt9u9SjHVYMlbs5CEJGVSczk0SG3y8P1lOWNDSRnMksZ\n" \
     74     "xWnHdP/ogcuYMuvK7UACNAF0zNddtzOhzcpNmejFj+WCHYY/UmPr2/Kf6t7Cxk2K\n" \
     75     "3cZ4tqWsiTmBT8Bknmah7L5DrhS+ZBJliDeFAA8fZHdMH0Xjr4UBp9kF90EMTdW1\n" \
     76     "Xr5uz7ZrMsYpYQI7mmyqV9SSjUg4iBXwVSoag1iDJ1K8Qg/L7Semgg==\n" \
     77     "-----END RSA PRIVATE KEY-----\n"
     78 
     79 /*
     80  * This loads the private key we defined earlier
     81  */
     82 static gnutls_x509_privkey_t test_tls_load_key(void)
     83 {
     84     gnutls_x509_privkey_t key;
     85     const gnutls_datum_t data = { (unsigned char *)PRIVATE_KEY,
     86                                   strlen(PRIVATE_KEY) };
     87     int err;
     88 
     89     err = gnutls_x509_privkey_init(&key);
     90     if (err < 0) {
     91         g_critical("Failed to init key %s", gnutls_strerror(err));
     92         abort();
     93     }
     94 
     95     err = gnutls_x509_privkey_import(key, &data,
     96                                      GNUTLS_X509_FMT_PEM);
     97     if (err < 0) {
     98         if (err != GNUTLS_E_BASE64_UNEXPECTED_HEADER_ERROR &&
     99             err != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
    100             g_critical("Failed to import key %s", gnutls_strerror(err));
    101             abort();
    102         }
    103 
    104         err = gnutls_x509_privkey_import_pkcs8(
    105             key, &data, GNUTLS_X509_FMT_PEM, NULL, 0);
    106         if (err < 0) {
    107             g_critical("Failed to import PKCS8 key %s", gnutls_strerror(err));
    108             abort();
    109         }
    110     }
    111 
    112     return key;
    113 }
    114 
    115 
    116 void test_tls_init(const char *keyfile)
    117 {
    118     qcrypto_init(&error_abort);
    119 
    120     if (asn1_array2tree(pkix_asn1_tab, &pkix_asn1, NULL) != ASN1_SUCCESS) {
    121         abort();
    122     }
    123 
    124     privkey = test_tls_load_key();
    125     if (!g_file_set_contents(keyfile, PRIVATE_KEY, -1, NULL)) {
    126         abort();
    127     }
    128 }
    129 
    130 
    131 void test_tls_cleanup(const char *keyfile)
    132 {
    133     asn1_delete_structure(&pkix_asn1);
    134     unlink(keyfile);
    135 }
    136 
    137 /*
    138  * Turns an ASN1 object into a DER encoded byte array
    139  */
    140 static void test_tls_der_encode(asn1_node src,
    141                                 const char *src_name,
    142                                 gnutls_datum_t *res)
    143 {
    144   int size;
    145   char *data = NULL;
    146 
    147   size = 0;
    148   asn1_der_coding(src, src_name, NULL, &size, NULL);
    149 
    150   data = g_new0(char, size);
    151 
    152   asn1_der_coding(src, src_name, data, &size, NULL);
    153 
    154   res->data = (unsigned char *)data;
    155   res->size = size;
    156 }
    157 
    158 
    159 static void
    160 test_tls_get_ipaddr(const char *addrstr,
    161                     char **data,
    162                     int *datalen)
    163 {
    164     struct addrinfo *res;
    165     struct addrinfo hints;
    166 
    167     memset(&hints, 0, sizeof(hints));
    168     hints.ai_flags = AI_NUMERICHOST;
    169     g_assert(getaddrinfo(addrstr, NULL, &hints, &res) == 0);
    170 
    171     if (res->ai_family == AF_INET) {
    172         struct sockaddr_in *in = (struct sockaddr_in *)res->ai_addr;
    173         *datalen = sizeof(in->sin_addr);
    174         *data = g_new(char, *datalen);
    175         memcpy(*data, &in->sin_addr, *datalen);
    176     } else if (res->ai_family == AF_INET6) {
    177         struct sockaddr_in6 *in = (struct sockaddr_in6 *)res->ai_addr;
    178         *datalen = sizeof(in->sin6_addr);
    179         *data = g_new(char, *datalen);
    180         memcpy(*data, &in->sin6_addr, *datalen);
    181     } else {
    182         g_assert_not_reached();
    183     }
    184     freeaddrinfo(res);
    185 }
    186 
    187 /*
    188  * This is a fairly lame x509 certificate generator.
    189  *
    190  * Do not copy/use this code for generating real certificates
    191  * since it leaves out many things that you would want in
    192  * certificates for real world usage.
    193  *
    194  * This is good enough only for doing tests of the QEMU
    195  * TLS certificate code
    196  */
    197 void
    198 test_tls_generate_cert(QCryptoTLSTestCertReq *req,
    199                        gnutls_x509_crt_t ca)
    200 {
    201     gnutls_x509_crt_t crt;
    202     int err;
    203     static char buffer[1024 * 1024];
    204     size_t size = sizeof(buffer);
    205     char serial[5] = { 1, 2, 3, 4, 0 };
    206     gnutls_datum_t der;
    207     time_t start = time(NULL) + (60 * 60 * req->start_offset);
    208     time_t expire = time(NULL) + (60 * 60 * (req->expire_offset
    209                                              ? req->expire_offset : 24));
    210 
    211     /*
    212      * Prepare our new certificate object
    213      */
    214     err = gnutls_x509_crt_init(&crt);
    215     if (err < 0) {
    216         g_critical("Failed to initialize certificate %s", gnutls_strerror(err));
    217         abort();
    218     }
    219     err = gnutls_x509_crt_set_key(crt, privkey);
    220     if (err < 0) {
    221         g_critical("Failed to set certificate key %s", gnutls_strerror(err));
    222         abort();
    223     }
    224 
    225     /*
    226      * A v3 certificate is required in order to be able
    227      * set any of the basic constraints, key purpose and
    228      * key usage data
    229      */
    230     gnutls_x509_crt_set_version(crt, 3);
    231 
    232     if (req->country) {
    233         err = gnutls_x509_crt_set_dn_by_oid(
    234             crt, GNUTLS_OID_X520_COUNTRY_NAME, 0,
    235             req->country, strlen(req->country));
    236         if (err < 0) {
    237             g_critical("Failed to set certificate country name %s",
    238                        gnutls_strerror(err));
    239             abort();
    240         }
    241     }
    242     if (req->cn) {
    243         err = gnutls_x509_crt_set_dn_by_oid(
    244             crt, GNUTLS_OID_X520_COMMON_NAME, 0,
    245             req->cn, strlen(req->cn));
    246         if (err < 0) {
    247             g_critical("Failed to set certificate common name %s",
    248                        gnutls_strerror(err));
    249             abort();
    250         }
    251     }
    252 
    253     /*
    254      * Setup the subject altnames, which are used
    255      * for hostname checks in live sessions
    256      */
    257     if (req->altname1) {
    258         err = gnutls_x509_crt_set_subject_alt_name(
    259             crt, GNUTLS_SAN_DNSNAME,
    260             req->altname1,
    261             strlen(req->altname1),
    262             GNUTLS_FSAN_APPEND);
    263         if (err < 0) {
    264             g_critical("Failed to set certificate alt name %s",
    265                        gnutls_strerror(err));
    266             abort();
    267         }
    268     }
    269     if (req->altname2) {
    270         err = gnutls_x509_crt_set_subject_alt_name(
    271             crt, GNUTLS_SAN_DNSNAME,
    272             req->altname2,
    273             strlen(req->altname2),
    274             GNUTLS_FSAN_APPEND);
    275         if (err < 0) {
    276             g_critical("Failed to set certificate %s alt name",
    277                        gnutls_strerror(err));
    278             abort();
    279         }
    280     }
    281 
    282     /*
    283      * IP address need to be put into the cert in their
    284      * raw byte form, not strings, hence this is a little
    285      * more complicated
    286      */
    287     if (req->ipaddr1) {
    288         char *data;
    289         int len;
    290 
    291         test_tls_get_ipaddr(req->ipaddr1, &data, &len);
    292 
    293         err = gnutls_x509_crt_set_subject_alt_name(
    294             crt, GNUTLS_SAN_IPADDRESS,
    295             data, len, GNUTLS_FSAN_APPEND);
    296         if (err < 0) {
    297             g_critical("Failed to set certificate alt name %s",
    298                        gnutls_strerror(err));
    299             abort();
    300         }
    301         g_free(data);
    302     }
    303     if (req->ipaddr2) {
    304         char *data;
    305         int len;
    306 
    307         test_tls_get_ipaddr(req->ipaddr2, &data, &len);
    308 
    309         err = gnutls_x509_crt_set_subject_alt_name(
    310             crt, GNUTLS_SAN_IPADDRESS,
    311             data, len, GNUTLS_FSAN_APPEND);
    312         if (err < 0) {
    313             g_critical("Failed to set certificate alt name %s",
    314                        gnutls_strerror(err));
    315             abort();
    316         }
    317         g_free(data);
    318     }
    319 
    320 
    321     /*
    322      * Basic constraints are used to decide if the cert
    323      * is for a CA or not. We can't use the convenient
    324      * gnutls API for setting this, since it hardcodes
    325      * the 'critical' field which we want control over
    326      */
    327     if (req->basicConstraintsEnable) {
    328         asn1_node ext = NULL;
    329 
    330         asn1_create_element(pkix_asn1, "PKIX1.BasicConstraints", &ext);
    331         asn1_write_value(ext, "cA",
    332                          req->basicConstraintsIsCA ? "TRUE" : "FALSE", 1);
    333         asn1_write_value(ext, "pathLenConstraint", NULL, 0);
    334         test_tls_der_encode(ext, "", &der);
    335         err = gnutls_x509_crt_set_extension_by_oid(
    336             crt, "2.5.29.19",
    337             der.data, der.size,
    338             req->basicConstraintsCritical);
    339         if (err < 0) {
    340             g_critical("Failed to set certificate basic constraints %s",
    341                        gnutls_strerror(err));
    342             g_free(der.data);
    343             abort();
    344         }
    345         asn1_delete_structure(&ext);
    346         g_free(der.data);
    347     }
    348 
    349     /*
    350      * Next up the key usage extension. Again we can't
    351      * use the gnutls API since it hardcodes the extension
    352      * to be 'critical'
    353      */
    354     if (req->keyUsageEnable) {
    355         asn1_node ext = NULL;
    356         char str[2];
    357 
    358         str[0] = req->keyUsageValue & 0xff;
    359         str[1] = (req->keyUsageValue >> 8) & 0xff;
    360 
    361         asn1_create_element(pkix_asn1, "PKIX1.KeyUsage", &ext);
    362         asn1_write_value(ext, "", str, 9);
    363         test_tls_der_encode(ext, "", &der);
    364         err = gnutls_x509_crt_set_extension_by_oid(
    365             crt, "2.5.29.15",
    366             der.data, der.size,
    367             req->keyUsageCritical);
    368         if (err < 0) {
    369             g_critical("Failed to set certificate key usage %s",
    370                        gnutls_strerror(err));
    371             g_free(der.data);
    372             abort();
    373         }
    374         asn1_delete_structure(&ext);
    375         g_free(der.data);
    376     }
    377 
    378     /*
    379      * Finally the key purpose extension. This time
    380      * gnutls has the opposite problem, always hardcoding
    381      * it to be non-critical. So once again we have to
    382      * set this the hard way building up ASN1 data ourselves
    383      */
    384     if (req->keyPurposeEnable) {
    385         asn1_node ext = NULL;
    386 
    387         asn1_create_element(pkix_asn1, "PKIX1.ExtKeyUsageSyntax", &ext);
    388         if (req->keyPurposeOID1) {
    389             asn1_write_value(ext, "", "NEW", 1);
    390             asn1_write_value(ext, "?LAST", req->keyPurposeOID1, 1);
    391         }
    392         if (req->keyPurposeOID2) {
    393             asn1_write_value(ext, "", "NEW", 1);
    394             asn1_write_value(ext, "?LAST", req->keyPurposeOID2, 1);
    395         }
    396         test_tls_der_encode(ext, "", &der);
    397         err = gnutls_x509_crt_set_extension_by_oid(
    398             crt, "2.5.29.37",
    399             der.data, der.size,
    400             req->keyPurposeCritical);
    401         if (err < 0) {
    402             g_critical("Failed to set certificate key purpose %s",
    403                        gnutls_strerror(err));
    404             g_free(der.data);
    405             abort();
    406         }
    407         asn1_delete_structure(&ext);
    408         g_free(der.data);
    409     }
    410 
    411     /*
    412      * Any old serial number will do, so lets pick 5
    413      */
    414     err = gnutls_x509_crt_set_serial(crt, serial, 5);
    415     if (err < 0) {
    416         g_critical("Failed to set certificate serial %s",
    417                    gnutls_strerror(err));
    418         abort();
    419     }
    420 
    421     err = gnutls_x509_crt_set_activation_time(crt, start);
    422     if (err < 0) {
    423         g_critical("Failed to set certificate activation %s",
    424                    gnutls_strerror(err));
    425         abort();
    426     }
    427     err = gnutls_x509_crt_set_expiration_time(crt, expire);
    428     if (err < 0) {
    429         g_critical("Failed to set certificate expiration %s",
    430                    gnutls_strerror(err));
    431         abort();
    432     }
    433 
    434 
    435     /*
    436      * If no 'ca' is set then we are self signing
    437      * the cert. This is done for the root CA certs
    438      */
    439     err = gnutls_x509_crt_sign2(crt, ca ? ca : crt, privkey,
    440                                 GNUTLS_DIG_SHA256, 0);
    441     if (err < 0) {
    442         g_critical("Failed to sign certificate %s",
    443                    gnutls_strerror(err));
    444         abort();
    445     }
    446 
    447     /*
    448      * Finally write the new cert out to disk
    449      */
    450     err = gnutls_x509_crt_export(
    451         crt, GNUTLS_X509_FMT_PEM, buffer, &size);
    452     if (err < 0) {
    453         g_critical("Failed to export certificate %s: %d",
    454                    gnutls_strerror(err), err);
    455         abort();
    456     }
    457 
    458     if (!g_file_set_contents(req->filename, buffer, -1, NULL)) {
    459         g_critical("Failed to write certificate %s",
    460                    req->filename);
    461         abort();
    462     }
    463 
    464     req->crt = crt;
    465 }
    466 
    467 
    468 void test_tls_write_cert_chain(const char *filename,
    469                                gnutls_x509_crt_t *certs,
    470                                size_t ncerts)
    471 {
    472     size_t i;
    473     size_t capacity = 1024, offset = 0;
    474     char *buffer = g_new0(char, capacity);
    475     int err;
    476 
    477     for (i = 0; i < ncerts; i++) {
    478         size_t len = capacity - offset;
    479     retry:
    480         err = gnutls_x509_crt_export(certs[i], GNUTLS_X509_FMT_PEM,
    481                                      buffer + offset, &len);
    482         if (err < 0) {
    483             if (err == GNUTLS_E_SHORT_MEMORY_BUFFER) {
    484                 buffer = g_renew(char, buffer, offset + len);
    485                 capacity = offset + len;
    486                 goto retry;
    487             }
    488             g_critical("Failed to export certificate chain %s: %d",
    489                        gnutls_strerror(err), err);
    490             abort();
    491         }
    492         offset += len;
    493     }
    494 
    495     if (!g_file_set_contents(filename, buffer, offset, NULL)) {
    496         abort();
    497     }
    498     g_free(buffer);
    499 }
    500 
    501 
    502 void test_tls_discard_cert(QCryptoTLSTestCertReq *req)
    503 {
    504     if (!req->crt) {
    505         return;
    506     }
    507 
    508     gnutls_x509_crt_deinit(req->crt);
    509     req->crt = NULL;
    510 
    511     if (getenv("QEMU_TEST_DEBUG_CERTS") == NULL) {
    512         unlink(req->filename);
    513     }
    514 }