LCOV - code coverage report
Current view: top level - common - sign.c (source / functions) Hit Total Coverage
Test: a simple test Lines: 0 155 0.0 %
Date: 2024-06-05 20:10:43 Functions: 0 13 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (C) 2018 Pengutronix
       3             :  *
       4             :  * This program is free software; you can redistribute it and/or modify it
       5             :  * under the terms of the GNU General Public License version 2 as published by
       6             :  * the Free Software Foundation.
       7             :  *
       8             :  * This program is distributed in the hope that it will be useful, but WITHOUT
       9             :  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      10             :  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
      11             :  * more details.
      12             :  *
      13             :  * You should have received a copy of the GNU General Public License along with
      14             :  * this program; if not, write to the Free Software Foundation, Inc., 51
      15             :  * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
      16             :  *
      17             :  * Author: Sascha Hauer
      18             :  */
      19             : 
      20             : #include <string.h>
      21             : #include <openssl/evp.h>
      22             : #include <openssl/opensslv.h>
      23             : #include <openssl/bio.h>
      24             : #include <openssl/pem.h>
      25             : #include <openssl/err.h>
      26             : #include <openssl/engine.h>
      27             : #include <openssl/cms.h>
      28             : #include <openssl/conf.h>
      29             : #include <err.h>
      30             : 
      31             : #include "linux_types.h"
      32             : #include "sign.h"
      33             : #include "ubifs.h"
      34             : #include "defs.h"
      35             : 
      36             : extern struct ubifs_info info_;
      37             : static struct ubifs_info *c = &info_;
      38             : 
      39             : EVP_MD_CTX *hash_md;
      40             : const EVP_MD *md;
      41             : 
      42           0 : static int match_string(const char * const *array, size_t n, const char *string)
      43             : {
      44             :         int index;
      45             :         const char *item;
      46             : 
      47           0 :         for (index = 0; index < n; index++) {
      48           0 :                 item = array[index];
      49           0 :                 if (!item)
      50             :                         break;
      51           0 :                 if (!strcmp(item, string))
      52             :                         return index;
      53             :         }
      54             : 
      55             :         return -EINVAL;
      56             : }
      57             : 
      58             : #include <linux/hash_info.h>
      59             : 
      60             : const char *const hash_algo_name[HASH_ALGO__LAST] = {
      61             :         [HASH_ALGO_MD4]         = "md4",
      62             :         [HASH_ALGO_MD5]         = "md5",
      63             :         [HASH_ALGO_SHA1]        = "sha1",
      64             :         [HASH_ALGO_RIPE_MD_160] = "rmd160",
      65             :         [HASH_ALGO_SHA256]      = "sha256",
      66             :         [HASH_ALGO_SHA384]      = "sha384",
      67             :         [HASH_ALGO_SHA512]      = "sha512",
      68             :         [HASH_ALGO_SHA224]      = "sha224",
      69             :         [HASH_ALGO_RIPE_MD_128] = "rmd128",
      70             :         [HASH_ALGO_RIPE_MD_256] = "rmd256",
      71             :         [HASH_ALGO_RIPE_MD_320] = "rmd320",
      72             :         [HASH_ALGO_WP_256]      = "wp256",
      73             :         [HASH_ALGO_WP_384]      = "wp384",
      74             :         [HASH_ALGO_WP_512]      = "wp512",
      75             :         [HASH_ALGO_TGR_128]     = "tgr128",
      76             :         [HASH_ALGO_TGR_160]     = "tgr160",
      77             :         [HASH_ALGO_TGR_192]     = "tgr192",
      78             :         [HASH_ALGO_SM3_256]     = "sm3-256",
      79             : };
      80             : 
      81           0 : static void display_openssl_errors(int l)
      82             : {
      83             :         const char *file;
      84             :         char buf[120];
      85             :         int e, line;
      86             : 
      87           0 :         if (ERR_peek_error() == 0)
      88           0 :                 return;
      89           0 :         fprintf(stderr, "At main.c:%d:\n", l);
      90             : 
      91           0 :         while ((e = ERR_get_error_line(&file, &line))) {
      92           0 :                 ERR_error_string(e, buf);
      93           0 :                 fprintf(stderr, "- SSL %s: %s:%d\n", buf, file, line);
      94             :         }
      95             : }
      96             : 
      97           0 : static void drain_openssl_errors(void)
      98             : {
      99             :         const char *file;
     100             :         int line;
     101             : 
     102           0 :         if (ERR_peek_error() == 0)
     103           0 :                 return;
     104           0 :         while (ERR_get_error_line(&file, &line)) {}
     105             : }
     106             : 
     107             : #define ssl_err_msg(fmt, ...) ({                        \
     108             :         display_openssl_errors(__LINE__);               \
     109             :         errmsg(fmt, ## __VA_ARGS__);                    \
     110             :         -1;                                             \
     111             : })
     112             : 
     113             : static const char *key_pass;
     114             : 
     115           0 : static int pem_pw_cb(char *buf, int len, __unused int w, __unused void *v)
     116             : {
     117             :         int pwlen;
     118             : 
     119           0 :         if (!key_pass)
     120             :                 return -1;
     121             : 
     122           0 :         pwlen = strlen(key_pass);
     123           0 :         if (pwlen >= len)
     124             :                 return -1;
     125             : 
     126           0 :         strcpy(buf, key_pass);
     127             : 
     128             :         /* If it's wrong, don't keep trying it. */
     129           0 :         key_pass = NULL;
     130             : 
     131           0 :         return pwlen;
     132             : }
     133             : 
     134           0 : static EVP_PKEY *read_private_key(const char *private_key_name, X509 **cert)
     135             : {
     136           0 :         EVP_PKEY *private_key = NULL;
     137             :         int err;
     138             : 
     139           0 :         *cert = NULL;
     140             : 
     141           0 :         if (!strncmp(private_key_name, "pkcs11:", 7)) {
     142             :                 ENGINE *e;
     143             :                 struct {
     144             :                         const char *url;
     145             :                         X509 *cert;
     146           0 :                 } parms = {
     147             :                         .url = private_key_name,
     148             :                 };
     149             : 
     150           0 :                 ENGINE_load_builtin_engines();
     151           0 :                 drain_openssl_errors();
     152           0 :                 e = ENGINE_by_id("pkcs11");
     153           0 :                 if (!e) {
     154           0 :                         ssl_err_msg("Load PKCS#11 ENGINE");
     155           0 :                         return NULL;
     156             :                 }
     157             : 
     158           0 :                 if (ENGINE_init(e)) {
     159           0 :                         drain_openssl_errors();
     160             :                 } else {
     161           0 :                         ssl_err_msg("ENGINE_init");
     162           0 :                         return NULL;
     163             :                 }
     164             : 
     165           0 :                 if (key_pass)
     166           0 :                         if (!ENGINE_ctrl_cmd_string(e, "PIN", key_pass, 0)) {
     167           0 :                                 ssl_err_msg("Set PKCS#11 PIN");
     168           0 :                                 return NULL;
     169             :                         }
     170             : 
     171           0 :                 private_key = ENGINE_load_private_key(e, private_key_name,
     172             :                                                       NULL, NULL);
     173             : 
     174           0 :                 err = ENGINE_ctrl_cmd(e, "LOAD_CERT_CTRL", 0, &parms, NULL, 0);
     175           0 :                 if (!err || !parms.cert) {
     176           0 :                         ssl_err_msg("Load certificate");
     177             :                 }
     178           0 :                 *cert = parms.cert;
     179           0 :                 fprintf(stderr, "Using cert %p\n", *cert);
     180             :         } else {
     181             :                 BIO *b;
     182             : 
     183           0 :                 b = BIO_new_file(private_key_name, "rb");
     184           0 :                 if (!b)
     185             :                         goto out;
     186             : 
     187           0 :                 private_key = PEM_read_bio_PrivateKey(b, NULL, pem_pw_cb,
     188             :                                                       NULL);
     189           0 :                 BIO_free(b);
     190             :         }
     191           0 : out:
     192           0 :         if (!private_key)
     193           0 :                 ssl_err_msg("failed opening private key %s", private_key_name);
     194             : 
     195             :         return private_key;
     196             : }
     197             : 
     198           0 : static X509 *read_x509(const char *x509_name)
     199             : {
     200             :         unsigned char buf[2];
     201           0 :         X509 *x509 = NULL;
     202             :         BIO *b;
     203             :         int n;
     204             : 
     205           0 :         b = BIO_new_file(x509_name, "rb");
     206           0 :         if (!b)
     207             :                 goto out;
     208             : 
     209             :         /* Look at the first two bytes of the file to determine the encoding */
     210           0 :         n = BIO_read(b, buf, 2);
     211           0 :         if (n != 2) {
     212           0 :                 if (BIO_should_retry(b))
     213           0 :                         errmsg("%s: Read wanted retry", x509_name);
     214           0 :                 if (n >= 0)
     215           0 :                         errmsg("%s: Short read", x509_name);
     216             :                 goto out;
     217             :         }
     218             : 
     219           0 :         if (BIO_reset(b))
     220             :                 goto out;
     221             : 
     222           0 :         if (buf[0] == 0x30 && buf[1] >= 0x81 && buf[1] <= 0x84)
     223             :                 /* Assume raw DER encoded X.509 */
     224           0 :                 x509 = d2i_X509_bio(b, NULL);
     225             :         else
     226             :                 /* Assume PEM encoded X.509 */
     227           0 :                 x509 = PEM_read_bio_X509(b, NULL, NULL, NULL);
     228             : 
     229           0 :         BIO_free(b);
     230             : 
     231           0 : out:
     232           0 :         if (!x509) {
     233           0 :                 ssl_err_msg("%s", x509_name);
     234           0 :                 return NULL;
     235             :         }
     236             : 
     237             :         return x509;
     238             : }
     239             : 
     240           0 : int hash_sign_node(const char *auth_key_filename, const char *auth_cert_filename,
     241             :                    void *buf, int *len, void *outbuf)
     242             : {
     243             :         EVP_PKEY *private_key;
     244           0 :         CMS_ContentInfo *cms = NULL;
     245           0 :         X509 *cert = NULL;
     246             :         BIO *bd, *bm;
     247             :         void *obuf;
     248             :         int ret;
     249             :         void *pret;
     250             : 
     251           0 :         ERR_load_crypto_strings();
     252           0 :         ERR_clear_error();
     253             : 
     254           0 :         key_pass = getenv("MKFS_UBIFS_SIGN_PIN");
     255             : 
     256           0 :         bm = BIO_new_mem_buf(buf, UBIFS_SB_NODE_SZ);
     257             : 
     258           0 :         private_key = read_private_key(auth_key_filename, &cert);
     259           0 :         if (!private_key)
     260             :                 return -1;
     261             : 
     262           0 :         if (!cert) {
     263           0 :                 if (!auth_cert_filename)
     264           0 :                         return errmsg("authentication certificate not provided (--auth-cert)");
     265           0 :                 cert = read_x509(auth_cert_filename);
     266             :         }
     267             : 
     268           0 :         if (!cert)
     269             :                 return -1;
     270             : 
     271           0 :         OpenSSL_add_all_digests();
     272           0 :         display_openssl_errors(__LINE__);
     273             : 
     274           0 :         cms = CMS_sign(NULL, NULL, NULL, NULL,
     275             :                        CMS_NOCERTS | CMS_PARTIAL | CMS_BINARY |
     276             :                        CMS_DETACHED | CMS_STREAM);
     277           0 :         if (!cms)
     278           0 :                 return errmsg("CMS_sign failed");
     279             : 
     280           0 :         pret = CMS_add1_signer(cms, cert, private_key, md,
     281             :                               CMS_NOCERTS | CMS_BINARY |
     282             :                               CMS_NOSMIMECAP | CMS_NOATTR);
     283           0 :         if (!pret)
     284           0 :                 return errmsg("CMS_add1_signer failed");
     285             : 
     286           0 :         ret = CMS_final(cms, bm, NULL, CMS_NOCERTS | CMS_BINARY);
     287           0 :         if (!ret)
     288           0 :                 return errmsg("CMS_final failed");
     289             : 
     290           0 :         bd = BIO_new(BIO_s_mem());
     291             : 
     292           0 :         ret = i2d_CMS_bio_stream(bd, cms, NULL, 0);
     293           0 :         if (!ret)
     294           0 :                 return errmsg("i2d_CMS_bio_stream failed");
     295             : 
     296           0 :         *len = BIO_get_mem_data(bd, &obuf);
     297             : 
     298           0 :         memcpy(outbuf, obuf, *len);
     299             : 
     300           0 :         BIO_free(bd);
     301           0 :         BIO_free(bm);
     302             : 
     303           0 :         return 0;
     304             : }
     305             : 
     306           0 : int hash_digest(const void *buf, unsigned int len, uint8_t *hash)
     307             : {
     308             :         int err;
     309             :         unsigned int md_len;
     310             : 
     311           0 :         err = EVP_DigestInit_ex(hash_md, md, NULL);
     312           0 :         if (!err)
     313           0 :                 return errmsg("Init hash digest failed");
     314           0 :         err = EVP_DigestUpdate(hash_md, buf, len);
     315           0 :         if (!err)
     316           0 :                 return errmsg("Update hash digest failed");
     317           0 :         err = EVP_DigestFinal_ex(hash_md, hash, &md_len);
     318           0 :         if (!err)
     319           0 :                 return errmsg("Finalize hash digest failed");
     320             : 
     321             :         return 0;
     322             : }
     323             : 
     324           0 : int hash_digest_init(void)
     325             : {
     326             :         int err;
     327             : 
     328           0 :         err = EVP_DigestInit_ex(hash_md, md, NULL);
     329           0 :         if (!err)
     330           0 :                 return errmsg("Init hash digest failed");
     331             : 
     332             :         return 0;
     333             : }
     334             : 
     335           0 : int hash_digest_update(const void *buf, int len)
     336             : {
     337             :         int err;
     338             : 
     339           0 :         err = EVP_DigestUpdate(hash_md, buf, len);
     340           0 :         if (!err)
     341           0 :                 return errmsg("Update hash digest failed");
     342             : 
     343             :         return 0;
     344             : }
     345             : 
     346           0 : int hash_digest_final(void *hash)
     347             : {
     348             :         int err;
     349             :         unsigned int md_len;
     350             : 
     351           0 :         err = EVP_DigestFinal_ex(hash_md, hash, &md_len);
     352           0 :         if (!err)
     353           0 :                 return errmsg("Finalize hash digest failed");
     354             : 
     355             :         return 0;
     356             : }
     357             : 
     358           0 : int init_authentication(const char *algo_name, int *hash_len, int *hash_algo)
     359             : {
     360           0 :         OPENSSL_config(NULL);
     361           0 :         OpenSSL_add_all_algorithms();
     362           0 :         ERR_load_crypto_strings();
     363             : 
     364           0 :         md = EVP_get_digestbyname(c->hash_algo_name);
     365           0 :         if (!md)
     366           0 :                 return errmsg("Unknown message digest %s", c->hash_algo_name);
     367             : 
     368           0 :         hash_md = EVP_MD_CTX_create();
     369           0 :         if (!hash_md)
     370           0 :                 return errmsg("Cannot create md ctx");
     371             : 
     372           0 :         *hash_len = EVP_MD_size(md);
     373           0 :         if (*hash_len < 0) {
     374           0 :                 EVP_MD_CTX_destroy(hash_md);
     375           0 :                 hash_md = NULL;
     376           0 :                 return errmsg("Cannot init hash len");
     377             :         }
     378             : 
     379           0 :         *hash_algo = match_string(hash_algo_name, HASH_ALGO__LAST, algo_name);
     380           0 :         if (*hash_algo < 0) {
     381           0 :                 EVP_MD_CTX_destroy(hash_md);
     382           0 :                 hash_md = NULL;
     383           0 :                 return errmsg("Unsupported message digest %s", algo_name);
     384             :         }
     385             : 
     386             :         return 0;
     387             : }
     388             : 
     389           0 : void exit_authentication(void)
     390             : {
     391           0 :         if (hash_md) {
     392           0 :                 EVP_MD_CTX_destroy(hash_md);
     393           0 :                 hash_md = NULL;
     394             :         }
     395           0 : }

Generated by: LCOV version 1.13