2 Unix SMB/CIFS implementation.
3 Helper functions for applying replicated objects
5 Copyright (C) Stefan Metzmacher <metze@samba.org> 2007
6 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2009
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.
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.
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/>.
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"
29 #include "../libcli/drsuapi/drsuapi.h"
30 #include "libcli/auth/libcli_auth.h"
31 #include "dsdb/samdb/samdb.h"
33 #include "lib/crypto/gnutls_helpers.h"
34 #include <gnutls/gnutls.h>
35 #include <gnutls/crypto.h>
37 static WERROR
drsuapi_decrypt_attribute_value(TALLOC_CTX
*mem_ctx
,
38 const DATA_BLOB
*gensec_skey
,
51 DATA_BLOB checked_buffer
;
53 DATA_BLOB plain_buffer
;
58 * users with rid == 0 should not exist
60 if (rid_crypt
&& rid
== 0) {
61 return WERR_DS_DRA_INVALID_PARAMETER
;
65 * the first 16 bytes at the beginning are the confounder
66 * followed by the 4 byte crc32 checksum
68 if (in
->length
< 20) {
69 return WERR_DS_DRA_INVALID_PARAMETER
;
71 confounder
= data_blob_const(in
->data
, 16);
72 enc_buffer
= data_blob_const(in
->data
+ 16, in
->length
- 16);
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!
79 * here the gensec session key is used and
80 * not the dcerpc ncacn_ip_tcp "SystemLibraryDTC" key!
84 * reference the encrypted buffer part and
85 * decrypt it using the created encryption key using arcfour
87 dec_buffer
= data_blob_const(enc_buffer
.data
, enc_buffer
.length
);
89 rc
= samba_gnutls_arcfour_confounded_md5(gensec_skey
,
92 SAMBA_GNUTLS_DECRYPT
);
94 result
= gnutls_error_to_werror(rc
, WERR_INTERNAL_ERROR
);
99 * the first 4 byte are the crc32 checksum
100 * of the remaining bytes
102 crc32_given
= IVAL(dec_buffer
.data
, 0);
103 crc32_calc
= crc32(0, Z_NULL
, 0);
104 crc32_calc
= crc32(crc32_calc
,
105 dec_buffer
.data
+ 4 ,
106 dec_buffer
.length
- 4);
107 checked_buffer
= data_blob_const(dec_buffer
.data
+ 4, dec_buffer
.length
- 4);
109 plain_buffer
= data_blob_talloc(mem_ctx
, checked_buffer
.data
, checked_buffer
.length
);
110 W_ERROR_HAVE_NO_MEMORY(plain_buffer
.data
);
112 if (crc32_given
!= crc32_calc
) {
113 result
= W_ERROR(HRES_ERROR_V(HRES_SEC_E_DECRYPT_FAILURE
));
117 * The following rid_crypt obfuscation isn't session specific
118 * and not really needed here, because we always know the rid of the
121 * some attributes with this 'additional encryption' include
122 * dBCSPwd, unicodePwd, ntPwdHistory, lmPwdHistory
124 * But for the rest of samba it's easier when we remove this static
128 uint32_t i
, num_hashes
;
130 if ((checked_buffer
.length
% 16) != 0) {
131 result
= WERR_DS_DRA_INVALID_PARAMETER
;
135 num_hashes
= plain_buffer
.length
/ 16;
136 for (i
= 0; i
< num_hashes
; i
++) {
137 uint32_t offset
= i
* 16;
138 rc
= sam_rid_crypt(rid
, checked_buffer
.data
+ offset
,
139 plain_buffer
.data
+ offset
,
140 SAMBA_GNUTLS_DECRYPT
);
142 result
= gnutls_error_to_werror(rc
, WERR_INTERNAL_ERROR
);
154 WERROR
drsuapi_decrypt_attribute(TALLOC_CTX
*mem_ctx
,
155 const DATA_BLOB
*gensec_skey
,
157 uint32_t dsdb_repl_flags
,
158 struct drsuapi_DsReplicaAttribute
*attr
)
162 DATA_BLOB plain_data
;
163 bool rid_crypt
= false;
165 if (attr
->value_ctr
.num_values
== 0) {
169 switch (attr
->attid
) {
170 case DRSUAPI_ATTID_dBCSPwd
:
171 case DRSUAPI_ATTID_unicodePwd
:
172 case DRSUAPI_ATTID_ntPwdHistory
:
173 case DRSUAPI_ATTID_lmPwdHistory
:
176 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
:
188 if (dsdb_repl_flags
& DSDB_REPL_FLAG_EXPECT_NO_SECRETS
) {
189 return WERR_TOO_MANY_SECRETS
;
192 if (attr
->value_ctr
.num_values
> 1) {
193 return WERR_DS_DRA_INVALID_PARAMETER
;
196 if (!attr
->value_ctr
.values
[0].blob
) {
197 return WERR_DS_DRA_INVALID_PARAMETER
;
200 enc_data
= attr
->value_ctr
.values
[0].blob
;
202 status
= drsuapi_decrypt_attribute_value(mem_ctx
,
208 W_ERROR_NOT_OK_RETURN(status
);
210 talloc_free(attr
->value_ctr
.values
[0].blob
->data
);
211 *attr
->value_ctr
.values
[0].blob
= plain_data
;
216 static WERROR
drsuapi_encrypt_attribute_value(TALLOC_CTX
*mem_ctx
,
217 const DATA_BLOB
*gensec_skey
,
223 DATA_BLOB rid_crypt_out
= data_blob(NULL
, 0);
224 DATA_BLOB confounder
;
226 DATA_BLOB enc_buffer
;
228 DATA_BLOB to_encrypt
;
235 * users with rid == 0 should not exist
237 if (rid_crypt
&& rid
== 0) {
238 return WERR_DS_DRA_INVALID_PARAMETER
;
242 * The following rid_crypt obfuscation isn't session specific
243 * and not really needed here, because we always know the rid of the
246 * some attributes with this 'additional encryption' include
247 * dBCSPwd, unicodePwd, ntPwdHistory, lmPwdHistory
249 * But for the rest of samba it's easier when we remove this static
253 uint32_t i
, num_hashes
;
254 rid_crypt_out
= data_blob_talloc(mem_ctx
, in
->data
, in
->length
);
255 W_ERROR_HAVE_NO_MEMORY(rid_crypt_out
.data
);
257 if ((rid_crypt_out
.length
% 16) != 0) {
258 return WERR_DS_DRA_INVALID_PARAMETER
;
261 num_hashes
= rid_crypt_out
.length
/ 16;
262 for (i
= 0; i
< num_hashes
; i
++) {
263 uint32_t offset
= i
* 16;
264 rc
= sam_rid_crypt(rid
, in
->data
+ offset
,
265 rid_crypt_out
.data
+ offset
,
266 SAMBA_GNUTLS_ENCRYPT
);
268 result
= gnutls_error_to_werror(rc
, WERR_INTERNAL_ERROR
);
276 * the first 16 bytes at the beginning are the confounder
277 * followed by the 4 byte crc32 checksum
280 enc_buffer
= data_blob_talloc(mem_ctx
, NULL
, in
->length
+20);
281 if (!enc_buffer
.data
) {
282 talloc_free(rid_crypt_out
.data
);
283 return WERR_NOT_ENOUGH_MEMORY
;
286 confounder
= data_blob_const(enc_buffer
.data
, 16);
287 generate_random_buffer(confounder
.data
, confounder
.length
);
290 * the first 4 byte are the crc32 checksum
291 * of the remaining bytes
293 crc32_calc
= crc32(0, Z_NULL
, 0);
294 crc32_calc
= crc32(crc32_calc
, in
->data
, in
->length
);
295 SIVAL(enc_buffer
.data
, 16, crc32_calc
);
298 * copy the plain buffer part and
299 * encrypt it using the created encryption key using arcfour
301 memcpy(enc_buffer
.data
+20, in
->data
, in
->length
);
302 talloc_free(rid_crypt_out
.data
);
304 to_encrypt
= data_blob_const(enc_buffer
.data
+16,
305 enc_buffer
.length
-16);
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!
312 * here the gensec session key is used and
313 * not the dcerpc ncacn_ip_tcp "SystemLibraryDTC" key!
316 rc
= samba_gnutls_arcfour_confounded_md5(gensec_skey
,
319 SAMBA_GNUTLS_ENCRYPT
);
321 result
= gnutls_error_to_werror(rc
, WERR_INTERNAL_ERROR
);
332 encrypt a DRSUAPI attribute ready for sending over the wire
333 Only some attribute types are encrypted
335 WERROR
drsuapi_encrypt_attribute(TALLOC_CTX
*mem_ctx
,
336 const DATA_BLOB
*gensec_skey
,
338 struct drsuapi_DsReplicaAttribute
*attr
)
341 DATA_BLOB
*plain_data
;
343 bool rid_crypt
= false;
345 if (attr
->value_ctr
.num_values
== 0) {
349 switch (attr
->attid
) {
350 case DRSUAPI_ATTID_dBCSPwd
:
351 case DRSUAPI_ATTID_unicodePwd
:
352 case DRSUAPI_ATTID_ntPwdHistory
:
353 case DRSUAPI_ATTID_lmPwdHistory
:
356 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
:
368 if (attr
->value_ctr
.num_values
> 1) {
369 return WERR_DS_DRA_INVALID_PARAMETER
;
372 if (!attr
->value_ctr
.values
[0].blob
) {
373 return WERR_DS_DRA_INVALID_PARAMETER
;
376 plain_data
= attr
->value_ctr
.values
[0].blob
;
378 status
= drsuapi_encrypt_attribute_value(mem_ctx
,
384 W_ERROR_NOT_OK_RETURN(status
);
386 talloc_free(attr
->value_ctr
.values
[0].blob
->data
);
387 *attr
->value_ctr
.values
[0].blob
= enc_data
;