LCOV - code coverage report
Current view: top level - libcli/drsuapi - repl_decrypt.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 127 148 85.8 %
Date: 2024-02-28 12:06:22 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       10800 : 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           8 :         DATA_BLOB confounder;
      45           8 :         DATA_BLOB enc_buffer;
      46             : 
      47           8 :         DATA_BLOB dec_buffer;
      48             : 
      49           8 :         uint32_t crc32_given;
      50           8 :         uint32_t crc32_calc;
      51           8 :         DATA_BLOB checked_buffer;
      52             : 
      53           8 :         DATA_BLOB plain_buffer;
      54           8 :         WERROR result;
      55           8 :         int rc;
      56             : 
      57             :         /*
      58             :          * users with rid == 0 should not exist
      59             :          */
      60       10800 :         if (rid_crypt && rid == 0) {
      61           1 :                 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       10799 :         if (in->length < 20) {
      69           1 :                 return WERR_DS_DRA_INVALID_PARAMETER;
      70             :         }
      71       10798 :         confounder = data_blob_const(in->data, 16);
      72       10798 :         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       10798 :         dec_buffer = data_blob_const(enc_buffer.data, enc_buffer.length);
      88             : 
      89       10798 :         rc = samba_gnutls_arcfour_confounded_md5(gensec_skey,
      90             :                                                  &confounder,
      91             :                                                  &dec_buffer,
      92             :                                                  SAMBA_GNUTLS_DECRYPT);
      93       10798 :         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       10798 :         crc32_given = IVAL(dec_buffer.data, 0);
     103       10798 :         crc32_calc = crc32(0, Z_NULL, 0);
     104       21596 :         crc32_calc = crc32(crc32_calc,
     105       10798 :                            dec_buffer.data + 4 ,
     106       10798 :                            dec_buffer.length - 4);
     107       10798 :         checked_buffer = data_blob_const(dec_buffer.data + 4, dec_buffer.length - 4);
     108             : 
     109       10798 :         plain_buffer = data_blob_talloc(mem_ctx, checked_buffer.data, checked_buffer.length);
     110       10798 :         W_ERROR_HAVE_NO_MEMORY(plain_buffer.data);
     111             : 
     112       10798 :         if (crc32_given != crc32_calc) {
     113           1 :                 result = W_ERROR(HRES_ERROR_V(HRES_SEC_E_DECRYPT_FAILURE));
     114           1 :                 goto out;
     115             :         }
     116             :         /*
     117             :          * The following rid_crypt obfuscation isn't session specific
     118             :          * and not really needed here, because we always 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       10797 :         if (rid_crypt) {
     128           3 :                 uint32_t i, num_hashes;
     129             : 
     130        6399 :                 if ((checked_buffer.length % 16) != 0) {
     131           1 :                         result = WERR_DS_DRA_INVALID_PARAMETER;
     132           1 :                         goto out;
     133             :                 }
     134             : 
     135        6398 :                 num_hashes = plain_buffer.length / 16;
     136       13459 :                 for (i = 0; i < num_hashes; i++) {
     137        7061 :                         uint32_t offset = i * 16;
     138        7061 :                         rc = sam_rid_crypt(rid, checked_buffer.data + offset,
     139        7059 :                                            plain_buffer.data + offset,
     140             :                                            SAMBA_GNUTLS_DECRYPT);
     141        7061 :                         if (rc != 0) {
     142           0 :                                 result = gnutls_error_to_werror(rc, WERR_INTERNAL_ERROR);
     143           0 :                                 goto out;
     144             :                         }
     145             :                 }
     146             :         }
     147             : 
     148       10796 :         *out = plain_buffer;
     149       10796 :         result = WERR_OK;
     150       10798 : out:
     151       10798 :         return result;
     152             : }
     153             : 
     154    11115780 : 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           0 :         WERROR status;
     161           0 :         DATA_BLOB *enc_data;
     162           0 :         DATA_BLOB plain_data;
     163    11115780 :         bool rid_crypt = false;
     164             : 
     165    11115780 :         if (attr->value_ctr.num_values == 0) {
     166         114 :                 return WERR_OK;
     167             :         }
     168             : 
     169    11115666 :         switch (attr->attid) {
     170        6396 :         case DRSUAPI_ATTID_dBCSPwd:
     171             :         case DRSUAPI_ATTID_unicodePwd:
     172             :         case DRSUAPI_ATTID_ntPwdHistory:
     173             :         case DRSUAPI_ATTID_lmPwdHistory:
     174        6396 :                 rid_crypt = true;
     175        6396 :                 break;
     176        4396 :         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        4396 :                 break;
     184    11104874 :         default:
     185    11104874 :                 return WERR_OK;
     186             :         }
     187             : 
     188       10792 :         if (dsdb_repl_flags & DSDB_REPL_FLAG_EXPECT_NO_SECRETS) {
     189           0 :                 return WERR_TOO_MANY_SECRETS;
     190             :         }
     191             : 
     192       10792 :         if (attr->value_ctr.num_values > 1) {
     193           0 :                 return WERR_DS_DRA_INVALID_PARAMETER;
     194             :         }
     195             : 
     196       10792 :         if (!attr->value_ctr.values[0].blob) {
     197           0 :                 return WERR_DS_DRA_INVALID_PARAMETER;
     198             :         }
     199             : 
     200       10792 :         enc_data        = attr->value_ctr.values[0].blob;
     201             : 
     202       10792 :         status = drsuapi_decrypt_attribute_value(mem_ctx,
     203             :                                                  gensec_skey,
     204             :                                                  rid_crypt,
     205             :                                                  rid,
     206             :                                                  enc_data,
     207             :                                                  &plain_data);
     208       10792 :         W_ERROR_NOT_OK_RETURN(status);
     209             : 
     210       10792 :         talloc_free(attr->value_ctr.values[0].blob->data);
     211       10792 :         *attr->value_ctr.values[0].blob = plain_data;
     212             : 
     213       10792 :         return WERR_OK;
     214             : }
     215             : 
     216       14375 : 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       14375 :         DATA_BLOB rid_crypt_out = data_blob(NULL, 0);
     224           4 :         DATA_BLOB confounder;
     225             : 
     226           4 :         DATA_BLOB enc_buffer;
     227             : 
     228           4 :         DATA_BLOB to_encrypt;
     229             : 
     230           4 :         uint32_t crc32_calc;
     231           4 :         WERROR result;
     232           4 :         int rc;
     233             : 
     234             :         /*
     235             :          * users with rid == 0 should not exist
     236             :          */
     237       14375 :         if (rid_crypt && rid == 0) {
     238           1 :                 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 always 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       14374 :         if (rid_crypt) {
     253           2 :                 uint32_t i, num_hashes;
     254        9694 :                 rid_crypt_out = data_blob_talloc(mem_ctx, in->data, in->length);
     255        9694 :                 W_ERROR_HAVE_NO_MEMORY(rid_crypt_out.data);
     256             : 
     257        9694 :                 if ((rid_crypt_out.length % 16) != 0) {
     258           1 :                         return WERR_DS_DRA_INVALID_PARAMETER;
     259             :                 }
     260             : 
     261        9693 :                 num_hashes = rid_crypt_out.length / 16;
     262       20251 :                 for (i = 0; i < num_hashes; i++) {
     263       10558 :                         uint32_t offset = i * 16;
     264       10558 :                         rc = sam_rid_crypt(rid, in->data + offset,
     265       10557 :                                            rid_crypt_out.data + offset,
     266             :                                            SAMBA_GNUTLS_ENCRYPT);
     267       10558 :                         if (rc != 0) {
     268           0 :                                 result = gnutls_error_to_werror(rc, WERR_INTERNAL_ERROR);
     269           0 :                                 goto out;
     270             :                         }
     271             :                 }
     272        9692 :                 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       14373 :         enc_buffer = data_blob_talloc(mem_ctx, NULL, in->length+20);
     281       14373 :         if (!enc_buffer.data) {
     282           0 :                 talloc_free(rid_crypt_out.data);
     283           0 :                 return WERR_NOT_ENOUGH_MEMORY;
     284           2 :         };
     285             :         
     286       14373 :         confounder = data_blob_const(enc_buffer.data, 16);
     287       14373 :         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       14373 :         crc32_calc = crc32(0, Z_NULL, 0);
     294       14373 :         crc32_calc = crc32(crc32_calc, in->data, in->length);
     295       14373 :         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       14373 :         memcpy(enc_buffer.data+20, in->data, in->length); 
     302       14373 :         talloc_free(rid_crypt_out.data);
     303             : 
     304       14373 :         to_encrypt = data_blob_const(enc_buffer.data+16,
     305       14373 :                                      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       14373 :         rc = samba_gnutls_arcfour_confounded_md5(gensec_skey,
     317             :                                                  &confounder,
     318             :                                                  &to_encrypt,
     319             :                                                  SAMBA_GNUTLS_ENCRYPT);
     320       14373 :         if (rc < 0) {
     321           0 :                 result = gnutls_error_to_werror(rc, WERR_INTERNAL_ERROR);
     322           0 :                 goto out;
     323             :         }
     324             : 
     325       14373 :         *out = enc_buffer;
     326       14373 :         result =  WERR_OK;
     327       14373 : out:
     328       14373 :         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     6907668 : 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           0 :         WERROR status;
     341           0 :         DATA_BLOB *plain_data;
     342           0 :         DATA_BLOB enc_data;
     343     6907668 :         bool rid_crypt = false;
     344             : 
     345     6907668 :         if (attr->value_ctr.num_values == 0) {
     346        1038 :                 return WERR_OK;
     347             :         }
     348             : 
     349     6906630 :         switch (attr->attid) {
     350        9692 :         case DRSUAPI_ATTID_dBCSPwd:
     351             :         case DRSUAPI_ATTID_unicodePwd:
     352             :         case DRSUAPI_ATTID_ntPwdHistory:
     353             :         case DRSUAPI_ATTID_lmPwdHistory:
     354        9692 :                 rid_crypt = true;
     355        9692 :                 break;
     356        4679 :         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        4679 :                 break;
     364     6892259 :         default:
     365     6892259 :                 return WERR_OK;
     366             :         }
     367             : 
     368       14371 :         if (attr->value_ctr.num_values > 1) {
     369           0 :                 return WERR_DS_DRA_INVALID_PARAMETER;
     370             :         }
     371             : 
     372       14371 :         if (!attr->value_ctr.values[0].blob) {
     373           0 :                 return WERR_DS_DRA_INVALID_PARAMETER;
     374             :         }
     375             : 
     376       14371 :         plain_data      = attr->value_ctr.values[0].blob;
     377             : 
     378       14371 :         status = drsuapi_encrypt_attribute_value(mem_ctx,
     379             :                                                  gensec_skey,
     380             :                                                  rid_crypt,
     381             :                                                  rid,
     382             :                                                  plain_data,
     383             :                                                  &enc_data);
     384       14371 :         W_ERROR_NOT_OK_RETURN(status);
     385             : 
     386       14371 :         talloc_free(attr->value_ctr.values[0].blob->data);
     387       14371 :         *attr->value_ctr.values[0].blob = enc_data;
     388             : 
     389       14371 :         return WERR_OK;
     390             : }
     391             : 

Generated by: LCOV version 1.14