LCOV - code coverage report
Current view: top level - lib/crypto - gnutls_sp800_108.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 52 64 81.2 %
Date: 2024-04-21 15:09:00 Functions: 3 3 100.0 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             :    Wrapper for gnutls key derivation functions
       4             : 
       5             :    Copyright (C) Stefan Metzmacher 2009
       6             :    Copyright (C) Catalyst.Net Ltd 2023
       7             : 
       8             :    This program is free software; you can redistribute it and/or modify
       9             :    it under the terms of the GNU General Public License as published by
      10             :    the Free Software Foundation; either version 3 of the License, or
      11             :    (at your option) any later version.
      12             : 
      13             :    This program is distributed in the hope that it will be useful,
      14             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :    GNU General Public License for more details.
      17             : 
      18             :    You should have received a copy of the GNU General Public License
      19             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      20             : 
      21             : */
      22             : 
      23             : #include "includes.h"
      24             : #include <gnutls/gnutls.h>
      25             : #include <gnutls/crypto.h>
      26             : #include "gnutls_helpers.h"
      27             : 
      28      169105 : static NTSTATUS samba_gnutls_sp800_108_derive_key_part(
      29             :         const gnutls_hmac_hd_t hmac_hnd,
      30             :         const uint8_t *FixedData,
      31             :         const size_t FixedData_len,
      32             :         const uint8_t *Label,
      33             :         const size_t Label_len,
      34             :         const uint8_t *Context,
      35             :         const size_t Context_len,
      36             :         const uint32_t L,
      37             :         const uint32_t i,
      38             :         uint8_t *digest)
      39             : {
      40        5829 :         uint8_t buf[4];
      41        5829 :         static const uint8_t zero = 0;
      42        5829 :         int rc;
      43             : 
      44      169105 :         PUSH_BE_U32(buf, 0, i);
      45      169105 :         rc = gnutls_hmac(hmac_hnd, buf, sizeof(buf));
      46      169105 :         if (rc < 0) {
      47           0 :                 return gnutls_error_to_ntstatus(rc,
      48             :                                                 NT_STATUS_HMAC_NOT_SUPPORTED);
      49             :         }
      50      169105 :         if (FixedData != NULL) {
      51         250 :                 rc = gnutls_hmac(hmac_hnd, FixedData, FixedData_len);
      52         250 :                 if (rc < 0) {
      53           0 :                         return gnutls_error_to_ntstatus(
      54             :                                 rc, NT_STATUS_HMAC_NOT_SUPPORTED);
      55             :                 }
      56             :         } else {
      57      168855 :                 rc = gnutls_hmac(hmac_hnd, Label, Label_len);
      58      168855 :                 if (rc < 0) {
      59           0 :                         return gnutls_error_to_ntstatus(
      60             :                                 rc, NT_STATUS_HMAC_NOT_SUPPORTED);
      61             :                 }
      62      168855 :                 rc = gnutls_hmac(hmac_hnd, &zero, 1);
      63      168855 :                 if (rc < 0) {
      64           0 :                         return gnutls_error_to_ntstatus(
      65             :                                 rc, NT_STATUS_HMAC_NOT_SUPPORTED);
      66             :                 }
      67      168855 :                 rc = gnutls_hmac(hmac_hnd, Context, Context_len);
      68      168855 :                 if (rc < 0) {
      69           0 :                         return gnutls_error_to_ntstatus(
      70             :                                 rc, NT_STATUS_HMAC_NOT_SUPPORTED);
      71             :                 }
      72      168855 :                 PUSH_BE_U32(buf, 0, L);
      73      168855 :                 rc = gnutls_hmac(hmac_hnd, buf, sizeof(buf));
      74      168855 :                 if (rc < 0) {
      75           0 :                         return gnutls_error_to_ntstatus(
      76             :                                 rc, NT_STATUS_HMAC_NOT_SUPPORTED);
      77             :                 }
      78             :         }
      79             : 
      80      169105 :         gnutls_hmac_output(hmac_hnd, digest);
      81             : 
      82      169105 :         return NT_STATUS_OK;
      83             : }
      84             : 
      85      162973 : static size_t ceiling_div(const size_t a, const size_t b)
      86             : {
      87      168424 :         return a / b + (a % b != 0);
      88             : }
      89             : 
      90             : /**
      91             :  * @brief Derive a key using the NIST SP 800‐108 algorithm.
      92             :  *
      93             :  * The details of the algorithm can be found at
      94             :  * https://csrc.nist.gov/pubs/sp/800/108/r1/final.
      95             :  *
      96             :  * @param KI            The key‐derivation key used as input.
      97             :  *
      98             :  * @param KI_len        The length of the key‐derivation key.
      99             :  *
     100             :  * @param FixedData     If non‐NULL, specifies fixed data to be used in place of
     101             :  *                      that constructed from the Label and Context parameters.
     102             :  *
     103             :  * @param FixedData_len The length of the fixed data, if it is present.
     104             :  *
     105             :  * @param Label         A label that identifies the purpose for the derived key.
     106             :  *                      Ignored if FixedData is non‐NULL.
     107             :  *
     108             :  * @param Label_len     The length of the label.
     109             :  *
     110             :  * @param Context       Information related to the derived key. Ignored if
     111             :  *                      FixedData is non‐NULL.
     112             :  *
     113             :  * @param Context_len   The length of the context data.
     114             :  *
     115             :  * @param algorithm     The HMAC algorithm to use.
     116             :  *
     117             :  * @param KO            A buffer to receive the derived key.
     118             :  *
     119             :  * @param KO_len        The length of the key to be derived.
     120             :  *
     121             :  * @return NT_STATUS_OK on success, an NT status error code otherwise.
     122             :  */
     123      168424 : NTSTATUS samba_gnutls_sp800_108_derive_key(
     124             :         const uint8_t *KI,
     125             :         size_t KI_len,
     126             :         const uint8_t *FixedData,
     127             :         size_t FixedData_len,
     128             :         const uint8_t *Label,
     129             :         size_t Label_len,
     130             :         const uint8_t *Context,
     131             :         size_t Context_len,
     132             :         const gnutls_mac_algorithm_t algorithm,
     133             :         uint8_t *KO,
     134             :         size_t KO_len)
     135             : {
     136      168424 :         gnutls_hmac_hd_t hmac_hnd = NULL;
     137      168424 :         const size_t digest_len = gnutls_hmac_get_len(algorithm);
     138        5451 :         uint32_t i;
     139      168424 :         uint32_t L = KO_len * 8;
     140        5451 :         size_t KO_idx;
     141      168424 :         NTSTATUS status = NT_STATUS_OK;
     142        5451 :         int rc;
     143             : 
     144      168424 :         if (KO_len > UINT32_MAX / 8) {
     145             :                 /* The calculation of L has overflowed. */
     146           0 :                 return NT_STATUS_INTERNAL_ERROR;
     147             :         }
     148             : 
     149      168424 :         if (digest_len == 0) {
     150           0 :                 return NT_STATUS_HMAC_NOT_SUPPORTED;
     151             :         }
     152             : 
     153             :         {
     154      168424 :                 const size_t n_iterations = ceiling_div(KO_len, digest_len);
     155             :                 /*
     156             :                  * To ensure that the counter values are distinct, n shall not
     157             :                  * be larger than 2ʳ−1, where r = 32. We have made sure that
     158             :                  * |KO| × 8 < 2³², and we know that n ≤ |KO| from its
     159             :                  * definition. Thus n ≤ |KO| ≤ |KO| × 8 < 2³², and so the
     160             :                  * requirement n ≤ 2³² − 1 must always hold.
     161             :                  */
     162      168424 :                 SMB_ASSERT(n_iterations <= UINT32_MAX);
     163             :         }
     164             : 
     165             :         /*
     166             :          * a simplified version of
     167             :          * "NIST Special Publication 800-108" section 5.1.
     168             :          */
     169      168424 :         rc = gnutls_hmac_init(&hmac_hnd,
     170             :                               algorithm,
     171             :                               KI,
     172             :                               KI_len);
     173      168424 :         if (rc < 0) {
     174           0 :                 return gnutls_error_to_ntstatus(rc,
     175             :                                                 NT_STATUS_HMAC_NOT_SUPPORTED);
     176             :         }
     177             : 
     178             :         /* (This loop would make an excellent candidate for parallelization.) */
     179             : 
     180      172899 :         for (KO_idx = 0, i = 1; KO_len - KO_idx >= digest_len;
     181        4475 :              KO_idx += digest_len, ++i)
     182             :         {
     183        4475 :                 status = samba_gnutls_sp800_108_derive_key_part(hmac_hnd,
     184             :                                                                 FixedData,
     185             :                                                                 FixedData_len,
     186             :                                                                 Label,
     187             :                                                                 Label_len,
     188             :                                                                 Context,
     189             :                                                                 Context_len,
     190             :                                                                 L,
     191             :                                                                 i,
     192             :                                                                 KO + KO_idx);
     193        4475 :                 if (!NT_STATUS_IS_OK(status)) {
     194           0 :                         goto out;
     195             :                 }
     196             :         }
     197             : 
     198      168424 :         if (KO_idx < KO_len) {
     199             :                 /* Get the last little bit. */
     200      164630 :                 uint8_t digest[digest_len];
     201      164630 :                 status = samba_gnutls_sp800_108_derive_key_part(hmac_hnd,
     202             :                                                                 FixedData,
     203             :                                                                 FixedData_len,
     204             :                                                                 Label,
     205             :                                                                 Label_len,
     206             :                                                                 Context,
     207             :                                                                 Context_len,
     208             :                                                                 L,
     209             :                                                                 i,
     210             :                                                                 digest);
     211      164630 :                 if (!NT_STATUS_IS_OK(status)) {
     212           0 :                         goto out;
     213             :                 }
     214             : 
     215      164630 :                 memcpy(KO + KO_idx, digest, KO_len - KO_idx);
     216             : 
     217      164630 :                 ZERO_ARRAY(digest);
     218             :         }
     219             : 
     220        3794 : out:
     221      168424 :         if (hmac_hnd != NULL) {
     222      168424 :                 gnutls_hmac_deinit(hmac_hnd, NULL);
     223             :         }
     224      168424 :         if (!NT_STATUS_IS_OK(status)) {
     225             :                 /* Hide the evidence. */
     226           0 :                 memset_s(KO, KO_len, 0, KO_idx);
     227             :         }
     228             : 
     229      168424 :         return status;
     230             : }

Generated by: LCOV version 1.14