LCOV - code coverage report
Current view: top level - libcli/drsuapi - repl_decrypt.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 101 124 81.5 %
Date: 2024-06-13 04:01:37 Functions: 4 4 100.0 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS implementation.
       3             :    Helper functions for applying replicated objects
       4             :    
       5             :    Copyright (C) Stefan Metzmacher <metze@samba.org> 2007
       6             :    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2009
       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 "../lib/util/dlinklist.h"
      25             : #include "librpc/gen_ndr/ndr_misc.h"
      26             : #include "librpc/gen_ndr/ndr_drsuapi.h"
      27             : #include "librpc/gen_ndr/ndr_drsblobs.h"
      28             : #include "zlib.h"
      29             : #include "../libcli/drsuapi/drsuapi.h"
      30             : #include "libcli/auth/libcli_auth.h"
      31             : #include "dsdb/samdb/samdb.h"
      32             : 
      33             : #include "lib/crypto/gnutls_helpers.h"
      34             : #include <gnutls/gnutls.h>
      35             : #include <gnutls/crypto.h>
      36             : 
      37        5531 : static WERROR drsuapi_decrypt_attribute_value(TALLOC_CTX *mem_ctx,
      38             :                                               const DATA_BLOB *gensec_skey,
      39             :                                               bool rid_crypt,
      40             :                                               uint32_t rid,
      41             :                                               const DATA_BLOB *in,
      42             :                                               DATA_BLOB *out)
      43             : {
      44             :         DATA_BLOB confounder;
      45             :         DATA_BLOB enc_buffer;
      46             : 
      47             :         DATA_BLOB dec_buffer;
      48             : 
      49             :         uint32_t crc32_given;
      50             :         uint32_t crc32_calc;
      51             :         DATA_BLOB checked_buffer;
      52             : 
      53             :         DATA_BLOB plain_buffer;
      54             :         WERROR result;
      55             :         int rc;
      56             : 
      57             :         /*
      58             :          * users with rid == 0 should not exist
      59             :          */
      60        5531 :         if (rid_crypt && rid == 0) {
      61           0 :                 return WERR_DS_DRA_INVALID_PARAMETER;
      62             :         }
      63             : 
      64             :         /* 
      65             :          * the first 16 bytes at the beginning are the confounder
      66             :          * followed by the 4 byte crc32 checksum
      67             :          */
      68        5531 :         if (in->length < 20) {
      69           0 :                 return WERR_DS_DRA_INVALID_PARAMETER;
      70             :         }
      71        5531 :         confounder = data_blob_const(in->data, 16);
      72        5531 :         enc_buffer = data_blob_const(in->data + 16, in->length - 16);
      73             : 
      74             :         /* 
      75             :          * decrypt with the encryption key, being md5 over the session
      76             :          * key followed by the confounder.  The parameter order to
      77             :          * samba_gnutls_arcfour_confounded_md5() matters for this!
      78             :          * 
      79             :          * here the gensec session key is used and
      80             :          * not the dcerpc ncacn_ip_tcp "SystemLibraryDTC" key!
      81             :          */
      82             : 
      83             :         /*
      84             :          * reference the encrypted buffer part and
      85             :          * decrypt it using the created encryption key using arcfour
      86             :          */
      87        5531 :         dec_buffer = data_blob_const(enc_buffer.data, enc_buffer.length);
      88             : 
      89        5531 :         rc = samba_gnutls_arcfour_confounded_md5(gensec_skey,
      90             :                                                  &confounder,
      91             :                                                  &dec_buffer,
      92             :                                                  SAMBA_GNUTLS_DECRYPT);
      93        5531 :         if (rc < 0) {
      94           0 :                 result = gnutls_error_to_werror(rc, WERR_INTERNAL_ERROR);
      95           0 :                 goto out;
      96             :         }
      97             : 
      98             :         /* 
      99             :          * the first 4 byte are the crc32 checksum
     100             :          * of the remaining bytes
     101             :          */
     102        5531 :         crc32_given = IVAL(dec_buffer.data, 0);
     103        5531 :         crc32_calc = crc32(0, Z_NULL, 0);
     104       11062 :         crc32_calc = crc32(crc32_calc,
     105        5531 :                            dec_buffer.data + 4 ,
     106        5531 :                            dec_buffer.length - 4);
     107        5531 :         checked_buffer = data_blob_const(dec_buffer.data + 4, dec_buffer.length - 4);
     108             : 
     109        5531 :         plain_buffer = data_blob_talloc(mem_ctx, checked_buffer.data, checked_buffer.length);
     110        5531 :         W_ERROR_HAVE_NO_MEMORY(plain_buffer.data);
     111             : 
     112        5531 :         if (crc32_given != crc32_calc) {
     113           0 :                 result = W_ERROR(HRES_ERROR_V(HRES_SEC_E_DECRYPT_FAILURE));
     114           0 :                 goto out;
     115             :         }
     116             :         /*
     117             :          * The following rid_crypt obfuscation isn't session specific
     118             :          * and not really needed here, because we allways know the rid of the
     119             :          * user account.
     120             :          *
     121             :          * some attributes with this 'additional encryption' include
     122             :          * dBCSPwd, unicodePwd, ntPwdHistory, lmPwdHistory
     123             :          *
     124             :          * But for the rest of samba it's easier when we remove this static
     125             :          * obfuscation here
     126             :          */
     127        5531 :         if (rid_crypt) {
     128             :                 uint32_t i, num_hashes;
     129             : 
     130        3626 :                 if ((checked_buffer.length % 16) != 0) {
     131           0 :                         result = WERR_DS_DRA_INVALID_PARAMETER;
     132           0 :                         goto out;
     133             :                 }
     134             : 
     135        3626 :                 num_hashes = plain_buffer.length / 16;
     136        7868 :                 for (i = 0; i < num_hashes; i++) {
     137        4242 :                         uint32_t offset = i * 16;
     138        4242 :                         rc = sam_rid_crypt(rid, checked_buffer.data + offset,
     139        4242 :                                            plain_buffer.data + offset,
     140             :                                            SAMBA_GNUTLS_DECRYPT);
     141        4242 :                         if (rc != 0) {
     142           0 :                                 result = gnutls_error_to_werror(rc, WERR_INTERNAL_ERROR);
     143           0 :                                 goto out;
     144             :                         }
     145             :                 }
     146             :         }
     147             : 
     148        5531 :         *out = plain_buffer;
     149        5531 :         result = WERR_OK;
     150        5531 : out:
     151        5531 :         return result;
     152             : }
     153             : 
     154     9747272 : WERROR drsuapi_decrypt_attribute(TALLOC_CTX *mem_ctx, 
     155             :                                  const DATA_BLOB *gensec_skey,
     156             :                                  uint32_t rid,
     157             :                                  uint32_t dsdb_repl_flags,
     158             :                                  struct drsuapi_DsReplicaAttribute *attr)
     159             : {
     160             :         WERROR status;
     161             :         DATA_BLOB *enc_data;
     162             :         DATA_BLOB plain_data;
     163     9747272 :         bool rid_crypt = false;
     164             : 
     165     9747272 :         if (attr->value_ctr.num_values == 0) {
     166          38 :                 return WERR_OK;
     167             :         }
     168             : 
     169     9747234 :         switch (attr->attid) {
     170        3626 :         case DRSUAPI_ATTID_dBCSPwd:
     171             :         case DRSUAPI_ATTID_unicodePwd:
     172             :         case DRSUAPI_ATTID_ntPwdHistory:
     173             :         case DRSUAPI_ATTID_lmPwdHistory:
     174        3626 :                 rid_crypt = true;
     175        3626 :                 break;
     176        1905 :         case DRSUAPI_ATTID_supplementalCredentials:
     177             :         case DRSUAPI_ATTID_priorValue:
     178             :         case DRSUAPI_ATTID_currentValue:
     179             :         case DRSUAPI_ATTID_trustAuthOutgoing:
     180             :         case DRSUAPI_ATTID_trustAuthIncoming:
     181             :         case DRSUAPI_ATTID_initialAuthOutgoing:
     182             :         case DRSUAPI_ATTID_initialAuthIncoming:
     183        1905 :                 break;
     184     9741703 :         default:
     185     9741703 :                 return WERR_OK;
     186             :         }
     187             : 
     188        5531 :         if (dsdb_repl_flags & DSDB_REPL_FLAG_EXPECT_NO_SECRETS) {
     189           0 :                 return WERR_TOO_MANY_SECRETS;
     190             :         }
     191             : 
     192        5531 :         if (attr->value_ctr.num_values > 1) {
     193           0 :                 return WERR_DS_DRA_INVALID_PARAMETER;
     194             :         }
     195             : 
     196        5531 :         if (!attr->value_ctr.values[0].blob) {
     197           0 :                 return WERR_DS_DRA_INVALID_PARAMETER;
     198             :         }
     199             : 
     200        5531 :         enc_data        = attr->value_ctr.values[0].blob;
     201             : 
     202        5531 :         status = drsuapi_decrypt_attribute_value(mem_ctx,
     203             :                                                  gensec_skey,
     204             :                                                  rid_crypt,
     205             :                                                  rid,
     206             :                                                  enc_data,
     207             :                                                  &plain_data);
     208        5531 :         W_ERROR_NOT_OK_RETURN(status);
     209             : 
     210        5531 :         talloc_free(attr->value_ctr.values[0].blob->data);
     211        5531 :         *attr->value_ctr.values[0].blob = plain_data;
     212             : 
     213        5531 :         return WERR_OK;
     214             : }
     215             : 
     216        6487 : static WERROR drsuapi_encrypt_attribute_value(TALLOC_CTX *mem_ctx,
     217             :                                               const DATA_BLOB *gensec_skey,
     218             :                                               bool rid_crypt,
     219             :                                               uint32_t rid,
     220             :                                               const DATA_BLOB *in,
     221             :                                               DATA_BLOB *out)
     222             : {
     223        6487 :         DATA_BLOB rid_crypt_out = data_blob(NULL, 0);
     224             :         DATA_BLOB confounder;
     225             : 
     226             :         DATA_BLOB enc_buffer;
     227             : 
     228             :         DATA_BLOB to_encrypt;
     229             : 
     230             :         uint32_t crc32_calc;
     231             :         WERROR result;
     232             :         int rc;
     233             : 
     234             :         /*
     235             :          * users with rid == 0 should not exist
     236             :          */
     237        6487 :         if (rid_crypt && rid == 0) {
     238           0 :                 return WERR_DS_DRA_INVALID_PARAMETER;
     239             :         }
     240             : 
     241             :         /*
     242             :          * The following rid_crypt obfuscation isn't session specific
     243             :          * and not really needed here, because we allways know the rid of the
     244             :          * user account.
     245             :          *
     246             :          * some attributes with this 'additional encryption' include
     247             :          * dBCSPwd, unicodePwd, ntPwdHistory, lmPwdHistory
     248             :          *
     249             :          * But for the rest of samba it's easier when we remove this static
     250             :          * obfuscation here
     251             :          */
     252        6487 :         if (rid_crypt) {
     253             :                 uint32_t i, num_hashes;
     254        4364 :                 rid_crypt_out = data_blob_talloc(mem_ctx, in->data, in->length);
     255        4364 :                 W_ERROR_HAVE_NO_MEMORY(rid_crypt_out.data);
     256             : 
     257        4364 :                 if ((rid_crypt_out.length % 16) != 0) {
     258           0 :                         return WERR_DS_DRA_INVALID_PARAMETER;
     259             :                 }
     260             : 
     261        4364 :                 num_hashes = rid_crypt_out.length / 16;
     262        9468 :                 for (i = 0; i < num_hashes; i++) {
     263        5104 :                         uint32_t offset = i * 16;
     264        5104 :                         rc = sam_rid_crypt(rid, in->data + offset,
     265        5104 :                                            rid_crypt_out.data + offset,
     266             :                                            SAMBA_GNUTLS_ENCRYPT);
     267        5104 :                         if (rc != 0) {
     268           0 :                                 result = gnutls_error_to_werror(rc, WERR_INTERNAL_ERROR);
     269           0 :                                 goto out;
     270             :                         }
     271             :                 }
     272        4364 :                 in = &rid_crypt_out;
     273             :         }
     274             : 
     275             :         /* 
     276             :          * the first 16 bytes at the beginning are the confounder
     277             :          * followed by the 4 byte crc32 checksum
     278             :          */
     279             : 
     280        6487 :         enc_buffer = data_blob_talloc(mem_ctx, NULL, in->length+20);
     281        6487 :         if (!enc_buffer.data) {
     282           0 :                 talloc_free(rid_crypt_out.data);
     283           0 :                 return WERR_NOT_ENOUGH_MEMORY;
     284             :         };
     285             :         
     286        6487 :         confounder = data_blob_const(enc_buffer.data, 16);
     287        6487 :         generate_random_buffer(confounder.data, confounder.length);
     288             : 
     289             :         /* 
     290             :          * the first 4 byte are the crc32 checksum
     291             :          * of the remaining bytes
     292             :          */
     293        6487 :         crc32_calc = crc32(0, Z_NULL, 0);
     294        6487 :         crc32_calc = crc32(crc32_calc, in->data, in->length);
     295        6487 :         SIVAL(enc_buffer.data, 16, crc32_calc);
     296             : 
     297             :         /*
     298             :          * copy the plain buffer part and 
     299             :          * encrypt it using the created encryption key using arcfour
     300             :          */
     301        6487 :         memcpy(enc_buffer.data+20, in->data, in->length); 
     302        6487 :         talloc_free(rid_crypt_out.data);
     303             : 
     304        6487 :         to_encrypt = data_blob_const(enc_buffer.data+16,
     305        6487 :                                      enc_buffer.length-16);
     306             : 
     307             :         /*
     308             :          * encrypt with the encryption key, being md5 over the session
     309             :          * key followed by the confounder.  The parameter order to
     310             :          * samba_gnutls_arcfour_confounded_md5() matters for this!
     311             :          *
     312             :          * here the gensec session key is used and
     313             :          * not the dcerpc ncacn_ip_tcp "SystemLibraryDTC" key!
     314             :          */
     315             : 
     316        6487 :         rc = samba_gnutls_arcfour_confounded_md5(gensec_skey,
     317             :                                                  &confounder,
     318             :                                                  &to_encrypt,
     319             :                                                  SAMBA_GNUTLS_ENCRYPT);
     320        6487 :         if (rc < 0) {
     321           0 :                 result = gnutls_error_to_werror(rc, WERR_INTERNAL_ERROR);
     322           0 :                 goto out;
     323             :         }
     324             : 
     325        6487 :         *out = enc_buffer;
     326        6487 :         result =  WERR_OK;
     327        6487 : out:
     328        6487 :         return result;
     329             : }
     330             : 
     331             : /*
     332             :   encrypt a DRSUAPI attribute ready for sending over the wire
     333             :   Only some attribute types are encrypted
     334             :  */
     335     5948308 : WERROR drsuapi_encrypt_attribute(TALLOC_CTX *mem_ctx, 
     336             :                                  const DATA_BLOB *gensec_skey,
     337             :                                  uint32_t rid,
     338             :                                  struct drsuapi_DsReplicaAttribute *attr)
     339             : {
     340             :         WERROR status;
     341             :         DATA_BLOB *plain_data;
     342             :         DATA_BLOB enc_data;
     343     5948308 :         bool rid_crypt = false;
     344             : 
     345     5948308 :         if (attr->value_ctr.num_values == 0) {
     346        1083 :                 return WERR_OK;
     347             :         }
     348             : 
     349     5947225 :         switch (attr->attid) {
     350        4364 :         case DRSUAPI_ATTID_dBCSPwd:
     351             :         case DRSUAPI_ATTID_unicodePwd:
     352             :         case DRSUAPI_ATTID_ntPwdHistory:
     353             :         case DRSUAPI_ATTID_lmPwdHistory:
     354        4364 :                 rid_crypt = true;
     355        4364 :                 break;
     356        2123 :         case DRSUAPI_ATTID_supplementalCredentials:
     357             :         case DRSUAPI_ATTID_priorValue:
     358             :         case DRSUAPI_ATTID_currentValue:
     359             :         case DRSUAPI_ATTID_trustAuthOutgoing:
     360             :         case DRSUAPI_ATTID_trustAuthIncoming:
     361             :         case DRSUAPI_ATTID_initialAuthOutgoing:
     362             :         case DRSUAPI_ATTID_initialAuthIncoming:
     363        2123 :                 break;
     364     5940738 :         default:
     365     5940738 :                 return WERR_OK;
     366             :         }
     367             : 
     368        6487 :         if (attr->value_ctr.num_values > 1) {
     369           0 :                 return WERR_DS_DRA_INVALID_PARAMETER;
     370             :         }
     371             : 
     372        6487 :         if (!attr->value_ctr.values[0].blob) {
     373           0 :                 return WERR_DS_DRA_INVALID_PARAMETER;
     374             :         }
     375             : 
     376        6487 :         plain_data      = attr->value_ctr.values[0].blob;
     377             : 
     378        6487 :         status = drsuapi_encrypt_attribute_value(mem_ctx,
     379             :                                                  gensec_skey,
     380             :                                                  rid_crypt,
     381             :                                                  rid,
     382             :                                                  plain_data,
     383             :                                                  &enc_data);
     384        6487 :         W_ERROR_NOT_OK_RETURN(status);
     385             : 
     386        6487 :         talloc_free(attr->value_ctr.values[0].blob->data);
     387        6487 :         *attr->value_ctr.values[0].blob = enc_data;
     388             : 
     389        6487 :         return WERR_OK;
     390             : }
     391             : 

Generated by: LCOV version 1.13