The Samba-Bugzilla – Attachment 10721 Details for
Bug 11097
Win8.1 Credentials Manager issue after KB2992611 on Samba domain due to missing ServerWrap in BackupKey
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch to impelement ServerWrap in BackupKey
ServerWrap.patch (text/plain), 135.55 KB, created by
Garming Sam
on 2015-02-13 05:06:25 UTC
(
hide
)
Description:
Patch to impelement ServerWrap in BackupKey
Filename:
MIME Type:
Creator:
Garming Sam
Created:
2015-02-13 05:06:25 UTC
Size:
135.55 KB
patch
obsolete
>From b51fa78974d2e57639ec5e8afbe98b57552a10f6 Mon Sep 17 00:00:00 2001 >From: Arvid Requate <requate@univention.de> >Date: Mon, 7 Jul 2014 17:39:51 +0200 >Subject: [PATCH 01/31] s4-backupkey: Ensure RSA modulus is 2048 bits > >RSA_generate_key_ex doesn't always generate a modulus of requested >bit length. Tests with Windows 7 clients showed that they decline >x509 certificates (MS-BKRP 2.2.1) in cases where the modulus length >is smaller than the specified 2048 bits. For the user this resulted >in DPAPI failing to retrieve stored credentials after the user password >has been changed at least two times. On the server side log.samba showed >that the client also called the as yet unlimplemented ServerWrap sub- >protocol function BACKUPKEY_BACKUP_KEY_GUID after it had called the >ClientWarp function BACKUPKEY_RETRIEVE_BACKUP_KEY_GUID. After >enabling DPAPI auditing on the Windows Clients the Event Viewer showed >Event-ID 4692 failing with a FailureReason value of 0x7a in these cases. > >Signed-off-by: Arvid Requate <requate@univention.de> >--- > source4/rpc_server/backupkey/dcesrv_backupkey.c | 15 ++++++++++----- > 1 file changed, 10 insertions(+), 5 deletions(-) > >diff --git a/source4/rpc_server/backupkey/dcesrv_backupkey.c b/source4/rpc_server/backupkey/dcesrv_backupkey.c >index 9020da7..7daa500 100644 >--- a/source4/rpc_server/backupkey/dcesrv_backupkey.c >+++ b/source4/rpc_server/backupkey/dcesrv_backupkey.c >@@ -759,6 +759,7 @@ static WERROR create_heimdal_rsa_key(TALLOC_CTX *ctx, hx509_context *hctx, > uint8_t *p0, *p; > size_t len; > int bits = 2048; >+ int RSA_returned_bits; > > *_rsa = NULL; > >@@ -776,11 +777,15 @@ static WERROR create_heimdal_rsa_key(TALLOC_CTX *ctx, hx509_context *hctx, > return WERR_INTERNAL_ERROR; > } > >- ret = RSA_generate_key_ex(rsa, bits, pub_expo, NULL); >- if(ret != 1) { >- RSA_free(rsa); >- BN_free(pub_expo); >- return WERR_INTERNAL_ERROR; >+ while (RSA_returned_bits != bits) { >+ ret = RSA_generate_key_ex(rsa, bits, pub_expo, NULL); >+ if(ret != 1) { >+ RSA_free(rsa); >+ BN_free(pub_expo); >+ return WERR_INTERNAL_ERROR; >+ } >+ RSA_returned_bits = BN_num_bits(rsa->n); >+ DEBUG(6, ("RSA_generate_key_ex returned %d Bits\n", RSA_returned_bits)); > } > BN_free(pub_expo); > >-- >1.9.1 > > >From 4102ac0c1dd0c1c37df2b5553839041896905ec3 Mon Sep 17 00:00:00 2001 >From: Arvid Requate <requate@univention.de> >Date: Mon, 7 Jul 2014 17:59:29 +0200 >Subject: [PATCH 02/31] s4-backupkey: Cert lifetime of 365 days, not secs > >hx509_ca_tbs_set_notAfter_lifetime expects the lifetime value in >in seconds. The Windows 7 client didn't seem to care that the lifetime >was only 6'03''. Two other TODOs in this implementation: > >* Since notBefore is not set explicietely to "now", the heimdal code > default of now-(24 hours) is applied. > >* Server side validity checks and cert renewal are missing. > >Signed-off-by: Arvid Requate <requate@univention.de> >--- > source4/rpc_server/backupkey/dcesrv_backupkey.c | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > >diff --git a/source4/rpc_server/backupkey/dcesrv_backupkey.c b/source4/rpc_server/backupkey/dcesrv_backupkey.c >index 7daa500..5abfa87 100644 >--- a/source4/rpc_server/backupkey/dcesrv_backupkey.c >+++ b/source4/rpc_server/backupkey/dcesrv_backupkey.c >@@ -994,7 +994,7 @@ static WERROR generate_bkrp_cert(TALLOC_CTX *ctx, struct dcesrv_call_state *dce_ > char *secret_name; > struct bkrp_exported_RSA_key_pair keypair; > enum ndr_err_code ndr_err; >- uint32_t nb_days_validity = 365; >+ uint32_t nb_days_validity = 3600 * 24 * 365; > > DEBUG(6, ("Trying to generate a certificate\n")); > hx509_context_init(&hctx); >-- >1.9.1 > > >From ea7d893a013211500dac16e856d7e4e9b311061a Mon Sep 17 00:00:00 2001 >From: Arvid Requate <requate@univention.de> >Date: Mon, 7 Jul 2014 18:12:47 +0200 >Subject: [PATCH 03/31] s4-backupkey: check for talloc failure > >Check for talloc_memdup failure for uniqueid.data. > >Signed-off-by: Arvid Requate <requate@univention.de> >--- > source4/rpc_server/backupkey/dcesrv_backupkey.c | 3 +++ > 1 file changed, 3 insertions(+) > >diff --git a/source4/rpc_server/backupkey/dcesrv_backupkey.c b/source4/rpc_server/backupkey/dcesrv_backupkey.c >index 5abfa87..4d75b02 100644 >--- a/source4/rpc_server/backupkey/dcesrv_backupkey.c >+++ b/source4/rpc_server/backupkey/dcesrv_backupkey.c >@@ -836,6 +836,9 @@ static WERROR self_sign_cert(TALLOC_CTX *ctx, hx509_context *hctx, hx509_request > int ret; > > uniqueid.data = talloc_memdup(ctx, guidblob->data, guidblob->length); >+ if (uniqueid.data == NULL) { >+ return WERR_NOMEM; >+ } > /* uniqueid is a bit string in which each byte represent 1 bit (1 or 0) > * so as 1 byte is 8 bits we need to provision 8 times more space as in the > * blob >-- >1.9.1 > > >From b0143130bd4beb9399af441cf243b9e18d4e6691 Mon Sep 17 00:00:00 2001 >From: Arvid Requate <requate@univention.de> >Date: Mon, 7 Jul 2014 18:15:37 +0200 >Subject: [PATCH 04/31] s4-backupkey: de-duplicate error handling > >Signed-off-by: Arvid Requate <requate@univention.de> >--- > source4/rpc_server/backupkey/dcesrv_backupkey.c | 59 +++++++++---------------- > 1 file changed, 20 insertions(+), 39 deletions(-) > >diff --git a/source4/rpc_server/backupkey/dcesrv_backupkey.c b/source4/rpc_server/backupkey/dcesrv_backupkey.c >index 4d75b02..5db7685 100644 >--- a/source4/rpc_server/backupkey/dcesrv_backupkey.c >+++ b/source4/rpc_server/backupkey/dcesrv_backupkey.c >@@ -849,77 +849,58 @@ static WERROR self_sign_cert(TALLOC_CTX *ctx, hx509_context *hctx, hx509_request > > ret = hx509_request_get_name(*hctx, *req, &subject); > if (ret !=0) { >- talloc_free(uniqueid.data); >- return WERR_INTERNAL_ERROR; >+ goto fail_subject; > } > ret = hx509_request_get_SubjectPublicKeyInfo(*hctx, *req, &spki); > if (ret !=0) { >- talloc_free(uniqueid.data); >- hx509_name_free(&subject); >- return WERR_INTERNAL_ERROR; >+ goto fail_spki; > } > > ret = hx509_ca_tbs_init(*hctx, &tbs); > if (ret !=0) { >- talloc_free(uniqueid.data); >- hx509_name_free(&subject); >- free_SubjectPublicKeyInfo(&spki); >- return WERR_INTERNAL_ERROR; >+ goto fail_tbs; > } > > ret = hx509_ca_tbs_set_spki(*hctx, tbs, &spki); > if (ret !=0) { >- talloc_free(uniqueid.data); >- hx509_name_free(&subject); >- free_SubjectPublicKeyInfo(&spki); >- hx509_ca_tbs_free(&tbs); >- return WERR_INTERNAL_ERROR; >+ goto fail; > } > ret = hx509_ca_tbs_set_subject(*hctx, tbs, subject); > if (ret !=0) { >- talloc_free(uniqueid.data); >- hx509_name_free(&subject); >- free_SubjectPublicKeyInfo(&spki); >- hx509_ca_tbs_free(&tbs); >- return WERR_INTERNAL_ERROR; >+ goto fail; > } > ret = hx509_ca_tbs_set_ca(*hctx, tbs, 1); > if (ret !=0) { >- talloc_free(uniqueid.data); >- hx509_name_free(&subject); >- free_SubjectPublicKeyInfo(&spki); >- hx509_ca_tbs_free(&tbs); >- return WERR_INTERNAL_ERROR; >+ goto fail; > } > ret = hx509_ca_tbs_set_notAfter_lifetime(*hctx, tbs, lifetime); > if (ret !=0) { >- talloc_free(uniqueid.data); >- hx509_name_free(&subject); >- free_SubjectPublicKeyInfo(&spki); >- hx509_ca_tbs_free(&tbs); >- return WERR_INTERNAL_ERROR; >+ goto fail; > } > ret = hx509_ca_tbs_set_unique(*hctx, tbs, &uniqueid, &uniqueid); > if (ret !=0) { >- talloc_free(uniqueid.data); >- hx509_name_free(&subject); >- free_SubjectPublicKeyInfo(&spki); >- hx509_ca_tbs_free(&tbs); >- return WERR_INTERNAL_ERROR; >+ goto fail; > } > ret = hx509_ca_sign_self(*hctx, tbs, *private_key, cert); > if (ret !=0) { >- talloc_free(uniqueid.data); >- hx509_name_free(&subject); >- free_SubjectPublicKeyInfo(&spki); >- hx509_ca_tbs_free(&tbs); >- return WERR_INTERNAL_ERROR; >+ goto fail; > } > hx509_name_free(&subject); > free_SubjectPublicKeyInfo(&spki); > hx509_ca_tbs_free(&tbs); > > return WERR_OK; >+ >+fail: >+ hx509_ca_tbs_free(&tbs); >+fail_tbs: >+ free_SubjectPublicKeyInfo(&spki); >+fail_spki: >+ hx509_name_free(&subject); >+fail_subject: >+ talloc_free(uniqueid.data); >+ talloc_free(serialnumber.data); >+ return WERR_INTERNAL_ERROR; > } > > static WERROR create_req(TALLOC_CTX *ctx, hx509_context *hctx, hx509_request *req, >-- >1.9.1 > > >From 80411a8114f589e64c0b50a6aafc43345906f87d Mon Sep 17 00:00:00 2001 >From: Arvid Requate <requate@univention.de> >Date: Mon, 7 Jul 2014 18:18:30 +0200 >Subject: [PATCH 05/31] s4-backupkey: Set defined cert serialnumber > >[MS-BKRP] 2.2.1 specifies that the serialnumber of the certificate >should be set identical to the subjectUniqueID. In fact certificates >generated by native AD have this field encoded in little-endian format. >See also >https://www.mail-archive.com/cifs-protocol@cifs.org/msg01364.html > >Signed-off-by: Arvid Requate <requate@univention.de> >--- > source4/rpc_server/backupkey/dcesrv_backupkey.c | 23 ++++++++++++++++++++++- > 1 file changed, 22 insertions(+), 1 deletion(-) > >diff --git a/source4/rpc_server/backupkey/dcesrv_backupkey.c b/source4/rpc_server/backupkey/dcesrv_backupkey.c >index 5db7685..f748cd1 100644 >--- a/source4/rpc_server/backupkey/dcesrv_backupkey.c >+++ b/source4/rpc_server/backupkey/dcesrv_backupkey.c >@@ -833,7 +833,8 @@ static WERROR self_sign_cert(TALLOC_CTX *ctx, hx509_context *hctx, hx509_request > hx509_name subject = NULL; > hx509_ca_tbs tbs; > struct heim_bit_string uniqueid; >- int ret; >+ struct heim_integer serialnumber; >+ int ret, i; > > uniqueid.data = talloc_memdup(ctx, guidblob->data, guidblob->length); > if (uniqueid.data == NULL) { >@@ -845,6 +846,22 @@ static WERROR self_sign_cert(TALLOC_CTX *ctx, hx509_context *hctx, hx509_request > */ > uniqueid.length = 8 * guidblob->length; > >+ serialnumber.data = talloc_array(ctx, uint8_t, >+ guidblob->length); >+ if (serialnumber.data == NULL) { >+ talloc_free(uniqueid.data); >+ return WERR_NOMEM; >+ } >+ >+ /* Native AD generates certificates with serialnumber in reversed notation */ >+ for (i = 0; i < guidblob->length; i++) { >+ uint8_t *reversed = (uint8_t *)serialnumber.data; >+ uint8_t *uncrypt = guidblob->data; >+ reversed[i] = uncrypt[guidblob->length - 1 - i]; >+ } >+ serialnumber.length = guidblob->length; >+ serialnumber.negative = 0; >+ > memset(&spki, 0, sizeof(spki)); > > ret = hx509_request_get_name(*hctx, *req, &subject); >@@ -881,6 +898,10 @@ static WERROR self_sign_cert(TALLOC_CTX *ctx, hx509_context *hctx, hx509_request > if (ret !=0) { > goto fail; > } >+ ret = hx509_ca_tbs_set_serialnumber(*hctx, tbs, &serialnumber); >+ if (ret !=0) { >+ goto fail; >+ } > ret = hx509_ca_sign_self(*hctx, tbs, *private_key, cert); > if (ret !=0) { > goto fail; >-- >1.9.1 > > >From 0c6569f45e50d87c55161432f43f07ab1485c501 Mon Sep 17 00:00:00 2001 >From: Arvid Requate <requate@univention.de> >Date: Mon, 7 Jul 2014 18:25:29 +0200 >Subject: [PATCH 06/31] s4-backupkey: Comply with [MS-BKRP] 2.2.1 > >[MS-BKRP] 2.2.1 specifies "The Common Name field of the Subject name >field SHOULD contain the name of the DNS domain assigned to the server." > >In fact Windows 7 clients don't seem to care. Also in certificates >generated by native AD the domain name (after CN=) is encoded as >UTF-16LE. Since hx509_parse_name only supports UTF-8 strings currently >we just leave the encoding as it is for now. > >Signed-off-by: Arvid Requate <requate@univention.de> >--- > source4/rpc_server/backupkey/dcesrv_backupkey.c | 3 +-- > 1 file changed, 1 insertion(+), 2 deletions(-) > >diff --git a/source4/rpc_server/backupkey/dcesrv_backupkey.c b/source4/rpc_server/backupkey/dcesrv_backupkey.c >index f748cd1..07af1c0 100644 >--- a/source4/rpc_server/backupkey/dcesrv_backupkey.c >+++ b/source4/rpc_server/backupkey/dcesrv_backupkey.c >@@ -1184,8 +1184,7 @@ static WERROR bkrp_do_retreive_client_wrap_key(struct dcesrv_call_state *dce_cal > if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { > /* Ok we can be in this case if there was no certs */ > struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx; >- char *dn = talloc_asprintf(mem_ctx, "CN=%s.%s", >- lpcfg_netbios_name(lp_ctx), >+ char *dn = talloc_asprintf(mem_ctx, "CN=%s", > lpcfg_realm(lp_ctx)); > > WERROR werr = generate_bkrp_cert(mem_ctx, dce_call, ldb_ctx, dn); >-- >1.9.1 > > >From e960ba0fe99684389d11dbe4203952605e8de90a Mon Sep 17 00:00:00 2001 >From: Arvid Requate <requate@univention.de> >Date: Mon, 7 Jul 2014 18:36:49 +0200 >Subject: [PATCH 07/31] s4-backupkey: Initialize ndr->switchlist for print > >ndr_print_bkrp_data_in_blob requires the level to be set in the >proper ndr->switch_list context. > >Signed-off-by: Arvid Requate <requate@univention.de> >--- > librpc/ndr/ndr_backupkey.c | 5 +++++ > 1 file changed, 5 insertions(+) > >diff --git a/librpc/ndr/ndr_backupkey.c b/librpc/ndr/ndr_backupkey.c >index ddbaeea..827bc69 100644 >--- a/librpc/ndr/ndr_backupkey.c >+++ b/librpc/ndr/ndr_backupkey.c >@@ -71,6 +71,11 @@ _PUBLIC_ void ndr_print_bkrp_BackupKey(struct ndr_print *ndr, const char *name, > ndr->depth--; > > level = backupkeyguid_to_uint(r->in.guidActionAgent); >+ ndr_err = ndr_print_set_switch_value(ndr, &inblob, level); >+ if (unlikely(!NDR_ERR_CODE_IS_SUCCESS(ndr_err))) { \ >+ DEBUG(0,("ERROR: ndr_print_bkrp_BackupKey ndr_print_set_switch_value failed: %d\n", ndr_err)); >+ return; >+ } > blob.data = r->in.data_in; > blob.length = r->in.data_in_len; > ndr_err = ndr_pull_union_blob(&blob, ndr, &inblob, level, >-- >1.9.1 > > >From 5bcfd42354bf5c019846b675636a2f4a9f87ac57 Mon Sep 17 00:00:00 2001 >From: Arvid Requate <requate@univention.de> >Date: Mon, 7 Jul 2014 18:43:05 +0200 >Subject: [PATCH 08/31] s4-backupkey: fix ndr_pull error on empty input > >[MS-BKRP] 3.1.4.1 specifies for BACKUPKEY_RETRIEVE_BACKUP_KEY_GUID that >the server must ignore the input data. This patch fixes > ndr_pull_error(11): Pull bytes 4 (../librpc/ndr/ndr_basic.c:148) > >Signed-off-by: Arvid Requate <requate@univention.de> >--- > librpc/idl/backupkey.idl | 5 ++++- > 1 file changed, 4 insertions(+), 1 deletion(-) > >diff --git a/librpc/idl/backupkey.idl b/librpc/idl/backupkey.idl >index e21030b..b504ca5 100644 >--- a/librpc/idl/backupkey.idl >+++ b/librpc/idl/backupkey.idl >@@ -47,6 +47,9 @@ interface backupkey > uint8 key[256]; > } bkrp_dc_serverwrap_key; > >+ [public] typedef struct { >+ } bkrp_empty; >+ > [public,gensize] typedef struct { > uint32 version; > uint32 encrypted_secret_len; >@@ -103,7 +106,7 @@ interface backupkey > > [public] typedef [nodiscriminant] union { > [case(BACKUPKEY_RESTORE_GUID_INTEGER)] bkrp_client_side_wrapped restore_req; >- [case(BACKUPKEY_RETRIEVE_BACKUP_KEY_GUID_INTEGER)] bkrp_client_side_wrapped cert_req; >+ [case(BACKUPKEY_RETRIEVE_BACKUP_KEY_GUID_INTEGER)] bkrp_empty empty; > } bkrp_data_in_blob; > > /******************/ >-- >1.9.1 > > >From d634b4d1198890188b4a4a541b214c184863b791 Mon Sep 17 00:00:00 2001 >From: Arvid Requate <requate@univention.de> >Date: Mon, 7 Jul 2014 18:48:41 +0200 >Subject: [PATCH 09/31] s4-backupkey: IDL for ServerWrap subprotocol > >This adds some IDL structs for the ServerWrap subprotocol, allowing >parsing of the incoming RPC calls and returning WERR_NOT_SUPPORTED >instead of WERR_INVALID_PARAM. > >Signed-off-by: Arvid Requate <requate@univention.de> >--- > librpc/idl/backupkey.idl | 26 ++++++++++++++++++++++++- > source4/rpc_server/backupkey/dcesrv_backupkey.c | 12 ++++++++++++ > 2 files changed, 37 insertions(+), 1 deletion(-) > >diff --git a/librpc/idl/backupkey.idl b/librpc/idl/backupkey.idl >index b504ca5..18098cd 100644 >--- a/librpc/idl/backupkey.idl >+++ b/librpc/idl/backupkey.idl >@@ -98,15 +98,39 @@ interface backupkey > uint8 hash[64]; > } bkrp_access_check_v3; > >+ [public] typedef struct { >+ [subcontext(0),subcontext_size(32),flag(NDR_REMAINING)] DATA_BLOB r3; >+ [subcontext(0),subcontext_size(20),flag(NDR_REMAINING)] DATA_BLOB mac; >+ dom_sid sid; >+ [subcontext(0),flag(NDR_REMAINING)] DATA_BLOB secret; >+ } bkrp_rc4encryptedpayload; >+ >+ [public] typedef struct { >+ [value(0x00000001)] uint32 magic; >+ uint32 payload_length; >+ uint32 cyphertext_length; >+ [subcontext(0),subcontext_size(16),flag(NDR_REMAINING)] DATA_BLOB guid_of_wrapping_key; >+ [subcontext(0),subcontext_size(68),flag(NDR_REMAINING)] DATA_BLOB r2; >+ [subcontext(0),flag(NDR_REMAINING)] DATA_BLOB rc4encryptedpayload; >+ } bkrp_server_side_wrapped; >+ >+ [public] typedef struct { >+ [flag(NDR_REMAINING)] DATA_BLOB opaque; >+ } bkrp_opaque_blob; >+ > typedef enum { > BACKUPKEY_INVALID_GUID_INTEGER = 0xFFFF, > BACKUPKEY_RESTORE_GUID_INTEGER = 0x0000, >- BACKUPKEY_RETRIEVE_BACKUP_KEY_GUID_INTEGER = 0x0001 >+ BACKUPKEY_RETRIEVE_BACKUP_KEY_GUID_INTEGER = 0x0001, >+ BACKUPKEY_RESTORE_GUID_WIN2K_INTEGER = 0x0002, >+ BACKUPKEY_BACKUP_GUID_INTEGER = 0x0003 > } bkrp_guid_to_integer; > > [public] typedef [nodiscriminant] union { > [case(BACKUPKEY_RESTORE_GUID_INTEGER)] bkrp_client_side_wrapped restore_req; > [case(BACKUPKEY_RETRIEVE_BACKUP_KEY_GUID_INTEGER)] bkrp_empty empty; >+ [case(BACKUPKEY_RESTORE_GUID_WIN2K_INTEGER)] bkrp_server_side_wrapped unsign_req; >+ [case(BACKUPKEY_BACKUP_GUID_INTEGER)] bkrp_opaque_blob sign_req; > } bkrp_data_in_blob; > > /******************/ >diff --git a/source4/rpc_server/backupkey/dcesrv_backupkey.c b/source4/rpc_server/backupkey/dcesrv_backupkey.c >index 07af1c0..9dc7951 100644 >--- a/source4/rpc_server/backupkey/dcesrv_backupkey.c >+++ b/source4/rpc_server/backupkey/dcesrv_backupkey.c >@@ -1308,6 +1308,18 @@ static WERROR dcesrv_bkrp_BackupKey(struct dcesrv_call_state *dce_call, > DEBUG(debuglevel, ("Client %s requested certificate for client wrapped secret\n", addr)); > error = bkrp_do_retreive_client_wrap_key(dce_call, mem_ctx, r, ldb_ctx); > } >+ >+ if (strncasecmp(GUID_string(mem_ctx, r->in.guidActionAgent), >+ BACKUPKEY_RESTORE_GUID_WIN2K, strlen(BACKUPKEY_RESTORE_GUID_WIN2K)) == 0) { >+ DEBUG(debuglevel, ("Client %s requested to decrypt a server side wrapped secret, not implemented yet\n", addr)); >+ return WERR_NOT_SUPPORTED; /* is this appropriate? */ >+ } >+ >+ if (strncasecmp(GUID_string(mem_ctx, r->in.guidActionAgent), >+ BACKUPKEY_BACKUP_GUID, strlen(BACKUPKEY_BACKUP_GUID)) == 0) { >+ DEBUG(debuglevel, ("Client %s requested a server wrapped secret, not implemented yet\n", addr)); >+ return WERR_NOT_SUPPORTED; /* is this appropriate? */ >+ } > } > /*else: I am a RODC so I don't handle backup key protocol */ > >-- >1.9.1 > > >From c80e06d230c27c7425c0db4f515263394902de8e Mon Sep 17 00:00:00 2001 >From: Arvid Requate <requate@univention.de> >Date: Mon, 7 Jul 2014 18:56:39 +0200 >Subject: [PATCH 10/31] s4-backupkey: typo fix > >Signed-off-by: Arvid Requate <requate@univention.de> >--- > source4/rpc_server/backupkey/dcesrv_backupkey.c | 4 ++-- > 1 file changed, 2 insertions(+), 2 deletions(-) > >diff --git a/source4/rpc_server/backupkey/dcesrv_backupkey.c b/source4/rpc_server/backupkey/dcesrv_backupkey.c >index 9dc7951..f08eb83 100644 >--- a/source4/rpc_server/backupkey/dcesrv_backupkey.c >+++ b/source4/rpc_server/backupkey/dcesrv_backupkey.c >@@ -1161,7 +1161,7 @@ static WERROR generate_bkrp_cert(TALLOC_CTX *ctx, struct dcesrv_call_state *dce_ > return WERR_OK; > } > >-static WERROR bkrp_do_retreive_client_wrap_key(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, >+static WERROR bkrp_do_retrieve_client_wrap_key(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, > struct bkrp_BackupKey *r ,struct ldb_context *ldb_ctx) > { > struct GUID guid; >@@ -1306,7 +1306,7 @@ static WERROR dcesrv_bkrp_BackupKey(struct dcesrv_call_state *dce_call, > if (strncasecmp(GUID_string(mem_ctx, r->in.guidActionAgent), > BACKUPKEY_RETRIEVE_BACKUP_KEY_GUID, strlen(BACKUPKEY_RETRIEVE_BACKUP_KEY_GUID)) == 0) { > DEBUG(debuglevel, ("Client %s requested certificate for client wrapped secret\n", addr)); >- error = bkrp_do_retreive_client_wrap_key(dce_call, mem_ctx, r, ldb_ctx); >+ error = bkrp_do_retrieve_client_wrap_key(dce_call, mem_ctx, r, ldb_ctx); > } > > if (strncasecmp(GUID_string(mem_ctx, r->in.guidActionAgent), >-- >1.9.1 > > >From f178db0918bc5d009fdd14bb1b808efd5a3e133a Mon Sep 17 00:00:00 2001 >From: Arvid Requate <requate@univention.de> >Date: Tue, 8 Jul 2014 16:12:13 +0200 >Subject: [PATCH 11/31] s4-backupkey: improve variable name > >Signed-off-by: Arvid Requate <requate@univention.de> >--- > source4/rpc_server/backupkey/dcesrv_backupkey.c | 4 ++-- > 1 file changed, 2 insertions(+), 2 deletions(-) > >diff --git a/source4/rpc_server/backupkey/dcesrv_backupkey.c b/source4/rpc_server/backupkey/dcesrv_backupkey.c >index f08eb83..4e4beab 100644 >--- a/source4/rpc_server/backupkey/dcesrv_backupkey.c >+++ b/source4/rpc_server/backupkey/dcesrv_backupkey.c >@@ -999,7 +999,7 @@ static WERROR generate_bkrp_cert(TALLOC_CTX *ctx, struct dcesrv_call_state *dce_ > char *secret_name; > struct bkrp_exported_RSA_key_pair keypair; > enum ndr_err_code ndr_err; >- uint32_t nb_days_validity = 3600 * 24 * 365; >+ uint32_t nb_seconds_validity = 3600 * 24 * 365; > > DEBUG(6, ("Trying to generate a certificate\n")); > hx509_context_init(&hctx); >@@ -1017,7 +1017,7 @@ static WERROR generate_bkrp_cert(TALLOC_CTX *ctx, struct dcesrv_call_state *dce_ > return WERR_INVALID_DATA; > } > >- w_err = self_sign_cert(ctx, &hctx, &req, nb_days_validity, &pk, &cert, &blob); >+ w_err = self_sign_cert(ctx, &hctx, &req, nb_seconds_validity, &pk, &cert, &blob); > if (!W_ERROR_IS_OK(w_err)) { > hx509_private_key_free(&pk); > hx509_context_free(&hctx); >-- >1.9.1 > > >From 84f4aff19b8062aeb74399195da7cf63616303c5 Mon Sep 17 00:00:00 2001 >From: Arvid Requate <requate@univention.de> >Date: Tue, 8 Jul 2014 17:25:53 +0200 >Subject: [PATCH 12/31] s4-backupkey: consistent naming of werr variable > >Signed-off-by: Arvid Requate <requate@univention.de> >--- > source4/rpc_server/backupkey/dcesrv_backupkey.c | 20 ++++++++++---------- > 1 file changed, 10 insertions(+), 10 deletions(-) > >diff --git a/source4/rpc_server/backupkey/dcesrv_backupkey.c b/source4/rpc_server/backupkey/dcesrv_backupkey.c >index 4e4beab..fb55875 100644 >--- a/source4/rpc_server/backupkey/dcesrv_backupkey.c >+++ b/source4/rpc_server/backupkey/dcesrv_backupkey.c >@@ -931,11 +931,11 @@ static WERROR create_req(TALLOC_CTX *ctx, hx509_context *hctx, hx509_request *re > SubjectPublicKeyInfo key; > > hx509_name name; >- WERROR w_err; >+ WERROR werr; > >- w_err = create_heimdal_rsa_key(ctx, hctx, signer, rsa); >- if (!W_ERROR_IS_OK(w_err)) { >- return w_err; >+ werr = create_heimdal_rsa_key(ctx, hctx, signer, rsa); >+ if (!W_ERROR_IS_OK(werr)) { >+ return werr; > } > > hx509_request_init(*hctx, req); >@@ -983,7 +983,7 @@ static WERROR create_req(TALLOC_CTX *ctx, hx509_context *hctx, hx509_request *re > static WERROR generate_bkrp_cert(TALLOC_CTX *ctx, struct dcesrv_call_state *dce_call, struct ldb_context *ldb_ctx, const char *dn) > { > heim_octet_string data; >- WERROR w_err; >+ WERROR werr; > RSA *rsa; > hx509_context hctx; > hx509_private_key pk; >@@ -1003,10 +1003,10 @@ static WERROR generate_bkrp_cert(TALLOC_CTX *ctx, struct dcesrv_call_state *dce_ > > DEBUG(6, ("Trying to generate a certificate\n")); > hx509_context_init(&hctx); >- w_err = create_req(ctx, &hctx, &req, &pk, &rsa, dn); >- if (!W_ERROR_IS_OK(w_err)) { >+ werr = create_req(ctx, &hctx, &req, &pk, &rsa, dn); >+ if (!W_ERROR_IS_OK(werr)) { > hx509_context_free(&hctx); >- return w_err; >+ return werr; > } > > status = GUID_to_ndr_blob(&guid, ctx, &blob); >@@ -1017,8 +1017,8 @@ static WERROR generate_bkrp_cert(TALLOC_CTX *ctx, struct dcesrv_call_state *dce_ > return WERR_INVALID_DATA; > } > >- w_err = self_sign_cert(ctx, &hctx, &req, nb_seconds_validity, &pk, &cert, &blob); >- if (!W_ERROR_IS_OK(w_err)) { >+ werr = self_sign_cert(ctx, &hctx, &req, nb_seconds_validity, &pk, &cert, &blob); >+ if (!W_ERROR_IS_OK(werr)) { > hx509_private_key_free(&pk); > hx509_context_free(&hctx); > return WERR_INVALID_DATA; >-- >1.9.1 > > >From 9bb87623e93303995876bacadf2a4cd844d60eed Mon Sep 17 00:00:00 2001 >From: Arvid Requate <requate@univention.de> >Date: Tue, 23 Dec 2014 18:56:20 +0100 >Subject: [PATCH 13/31] s4:torture/rpc/backupkey: Require 2048 bit RSA key > >Signed-off-by: Arvid Requate <requate@univention.de> > >(fixed cleanup of memory) > >Signed-off-by: Andrew Bartlett <abartlet@samba.org> >--- > source4/torture/rpc/backupkey.c | 75 +++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 75 insertions(+) > >diff --git a/source4/torture/rpc/backupkey.c b/source4/torture/rpc/backupkey.c >index 75f756c..f74cded 100644 >--- a/source4/torture/rpc/backupkey.c >+++ b/source4/torture/rpc/backupkey.c >@@ -30,6 +30,7 @@ > #include <system/network.h> > #include <hx509.h> > #include <der.h> >+#include <hcrypto/rsa.h> > > > /* Our very special and valued secret */ >@@ -1034,6 +1035,77 @@ static bool test_RestoreGUID_badhashaccesscheck(struct torture_context *tctx, > return true; > } > >+/* >+ * Check that the RSA modulus in the certificate of the DCs has 2048 bits. >+ */ >+static bool test_RetreiveBackupKeyGUID_2048bits(struct torture_context *tctx, >+ struct dcerpc_pipe *p) >+{ >+ struct dcerpc_binding_handle *b = p->binding_handle; >+ DATA_BLOB out_blob; >+ struct bkrp_BackupKey *r = createRetreiveBackupKeyGUIDStruct(tctx, p, 2, &out_blob); >+ enum dcerpc_AuthType auth_type; >+ enum dcerpc_AuthLevel auth_level; >+ >+ hx509_context hctx; >+ int hret; >+ hx509_cert cert; >+ SubjectPublicKeyInfo spki; >+ RSA *rsa; >+ int RSA_returned_bits; >+ >+ hx509_context_init(&hctx); >+ >+ if (r == NULL) { >+ return false; >+ } >+ >+ dcerpc_binding_handle_auth_info(b, &auth_type, &auth_level); >+ >+ if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) { >+ const unsigned char *spki_spk_data; >+ torture_assert_ntstatus_ok(tctx, >+ dcerpc_bkrp_BackupKey_r(b, tctx, r), >+ "Get GUID"); >+ >+ out_blob.length = *r->out.data_out_len; >+ >+ hret = hx509_cert_init_data(hctx, out_blob.data, out_blob.length, &cert); >+ torture_assert_int_equal(tctx, hret, 0, "hx509_cert_init_data failed"); >+ >+ hret = hx509_cert_get_SPKI(hctx, cert , &spki); >+ torture_assert_int_equal(tctx, hret, 0, "hx509_cert_get_SPKI failed"); >+ >+ /* We must take a copy, as d2i_RSAPublicKey *changes* the input parameter */ >+ spki_spk_data = spki.subjectPublicKey.data; >+ rsa = d2i_RSAPublicKey(NULL, &spki_spk_data, spki.subjectPublicKey.length / 8); >+ torture_assert_int_equal(tctx, rsa != NULL, 1, "d2i_RSAPublicKey failed"); >+ >+ RSA_returned_bits = BN_num_bits(rsa->n); >+ torture_assert_int_equal(tctx, >+ RSA_returned_bits, >+ 2048, >+ "RSA Key doesn't have 2048 bits"); >+ >+ RSA_free(rsa); >+ >+ /* >+ * Because we prevented spki from being changed above, >+ * we can now safely call this to free it >+ */ >+ free_SubjectPublicKeyInfo(&spki); >+ hx509_cert_free(cert); >+ hx509_context_free(&hctx); >+ >+ } else { >+ torture_assert_ntstatus_equal(tctx, >+ dcerpc_bkrp_BackupKey_r(b, tctx, r), >+ NT_STATUS_ACCESS_DENIED, >+ "Get GUID"); >+ } >+ return true; >+} >+ > struct torture_suite *torture_rpc_backupkey(TALLOC_CTX *mem_ctx) > { > struct torture_rpc_tcase *tcase; >@@ -1080,5 +1152,8 @@ struct torture_suite *torture_rpc_backupkey(TALLOC_CTX *mem_ctx) > torture_rpc_tcase_add_test(tcase, "empty_request_restore_guid", > test_RestoreGUID_emptyrequest); > >+ torture_rpc_tcase_add_test(tcase, "retreive_backup_key_guid_2048_bits", >+ test_RetreiveBackupKeyGUID_2048bits); >+ > return suite; > } >-- >1.9.1 > > >From 120a8c21aa47876cbf1aa9e34bce889d67336e5d Mon Sep 17 00:00:00 2001 >From: Andrew Bartlett <abartlet@samba.org> >Date: Wed, 11 Feb 2015 09:51:27 +1300 >Subject: [PATCH 14/31] torture-backupkey: Add consistent assertions that > createRestoreGUIDStruct() suceeds > >Signed-off-by: Andrew Bartlett <abartlet@samba.org> >--- > source4/torture/rpc/backupkey.c | 13 ++++++++++++- > 1 file changed, 12 insertions(+), 1 deletion(-) > >diff --git a/source4/torture/rpc/backupkey.c b/source4/torture/rpc/backupkey.c >index f74cded..7f5676a 100644 >--- a/source4/torture/rpc/backupkey.c >+++ b/source4/torture/rpc/backupkey.c >@@ -767,6 +767,7 @@ static bool test_RestoreGUID_ko(struct torture_context *tctx, > if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) { > struct bkrp_BackupKey *r = createRestoreGUIDStruct(tctx, p, 2, &out_blob, > true, false, false, false, false, false, false); >+ torture_assert(tctx, r != NULL, "createRestoreGUIDStruct failed"); > torture_assert_ntstatus_ok(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r), "Restore GUID"); > out_blob.length = *r->out.data_out_len; > ndr_err = ndr_pull_struct_blob(&out_blob, tctx, &resp, (ndr_pull_flags_fn_t)ndr_pull_bkrp_client_side_unwrapped); >@@ -795,6 +796,7 @@ static bool test_RestoreGUID_wrongversion(struct torture_context *tctx, > if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) { > struct bkrp_BackupKey *r = createRestoreGUIDStruct(tctx, p, 2, &out_blob, > false, true, false, false, false, false, false); >+ torture_assert(tctx, r != NULL, "createRestoreGUIDStruct failed"); > torture_assert_ntstatus_ok(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r), "Restore GUID"); > out_blob.length = *r->out.data_out_len; > ndr_err = ndr_pull_struct_blob(&out_blob, tctx, &resp, (ndr_pull_flags_fn_t)ndr_pull_bkrp_client_side_unwrapped); >@@ -823,6 +825,7 @@ static bool test_RestoreGUID_wronguser(struct torture_context *tctx, > if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) { > struct bkrp_BackupKey *r = createRestoreGUIDStruct(tctx, p, 2, &out_blob, > false, false, true, false, false, false, false); >+ torture_assert(tctx, r != NULL, "createRestoreGUIDStruct failed"); > torture_assert_ntstatus_ok(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r), "Restore GUID"); > out_blob.length = *r->out.data_out_len; > ndr_err = ndr_pull_struct_blob(&out_blob, tctx, &resp, (ndr_pull_flags_fn_t)ndr_pull_bkrp_client_side_unwrapped); >@@ -851,6 +854,7 @@ static bool test_RestoreGUID_v3(struct torture_context *tctx, > if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) { > struct bkrp_BackupKey *r = createRestoreGUIDStruct(tctx, p, 3, &out_blob, > false, false, false, false, false, false, false); >+ torture_assert(tctx, r != NULL, "createRestoreGUIDStruct failed"); > torture_assert_ntstatus_ok(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r), "Restore GUID"); > out_blob.length = *r->out.data_out_len; > ndr_err = ndr_pull_struct_blob(&out_blob, tctx, &resp, (ndr_pull_flags_fn_t)ndr_pull_bkrp_client_side_unwrapped); >@@ -880,6 +884,7 @@ static bool test_RestoreGUID(struct torture_context *tctx, > if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) { > struct bkrp_BackupKey *r = createRestoreGUIDStruct(tctx, p, 2, &out_blob, > false, false, false, false, false, false, false); >+ torture_assert(tctx, r != NULL, "createRestoreGUIDStruct failed"); > torture_assert_ntstatus_ok(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r), "Restore GUID"); > out_blob.length = *r->out.data_out_len; > ndr_err = ndr_pull_struct_blob(&out_blob, tctx, &resp, (ndr_pull_flags_fn_t)ndr_pull_bkrp_client_side_unwrapped); >@@ -909,6 +914,7 @@ static bool test_RestoreGUID_badmagiconsecret(struct torture_context *tctx, > if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) { > struct bkrp_BackupKey *r = createRestoreGUIDStruct(tctx, p, 3, &out_blob, > false, false, false, true, false, false, false); >+ torture_assert(tctx, r != NULL, "createRestoreGUIDStruct failed"); > torture_assert_ntstatus_ok(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r), "Restore GUID"); > out_blob.length = *r->out.data_out_len; > ndr_err = ndr_pull_struct_blob(&out_blob, tctx, &resp, (ndr_pull_flags_fn_t)ndr_pull_bkrp_client_side_unwrapped); >@@ -936,7 +942,7 @@ static bool test_RestoreGUID_emptyrequest(struct torture_context *tctx, > struct bkrp_BackupKey *r = createRestoreGUIDStruct(tctx, p, 3, &out_blob, > false, false, false, true, false, false, true); > >- torture_assert_int_equal(tctx, r != NULL, 1, "Error while creating the restoreGUID struct"); >+ torture_assert(tctx, r != NULL, "createRestoreGUIDStruct failed"); > r->in.data_in = talloc(tctx, uint8_t); > r->in.data_in_len = 0; > r->in.param = 0; >@@ -966,6 +972,7 @@ static bool test_RestoreGUID_badcertguid(struct torture_context *tctx, > if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) { > struct bkrp_BackupKey *r = createRestoreGUIDStruct(tctx, p, 3, &out_blob, > false, false, false, false, false, false, true); >+ torture_assert(tctx, r != NULL, "createRestoreGUIDStruct() failed"); > torture_assert_ntstatus_ok(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r), "Restore GUID"); > out_blob.length = *r->out.data_out_len; > ndr_err = ndr_pull_struct_blob(&out_blob, tctx, &resp, (ndr_pull_flags_fn_t)ndr_pull_bkrp_client_side_unwrapped); >@@ -994,6 +1001,7 @@ static bool test_RestoreGUID_badmagicaccesscheck(struct torture_context *tctx, > if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) { > struct bkrp_BackupKey *r = createRestoreGUIDStruct(tctx, p, 2, &out_blob, > false, false, false, false, true, false, false); >+ torture_assert(tctx, r != NULL, "createRestoreGUIDStruct failed"); > torture_assert_ntstatus_ok(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r), "Restore GUID"); > out_blob.length = *r->out.data_out_len; > ndr_err = ndr_pull_struct_blob(&out_blob, tctx, &resp, (ndr_pull_flags_fn_t)ndr_pull_bkrp_client_side_unwrapped); >@@ -1022,6 +1030,7 @@ static bool test_RestoreGUID_badhashaccesscheck(struct torture_context *tctx, > if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) { > struct bkrp_BackupKey *r = createRestoreGUIDStruct(tctx, p, 2, &out_blob, > false, false, false, false, false, true, false); >+ torture_assert(tctx, r != NULL, "createRestoreGUIDStruct failed"); > torture_assert_ntstatus_ok(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r), "Restore GUID"); > out_blob.length = *r->out.data_out_len; > ndr_err = ndr_pull_struct_blob(&out_blob, tctx, &resp, (ndr_pull_flags_fn_t)ndr_pull_bkrp_client_side_unwrapped); >@@ -1054,6 +1063,8 @@ static bool test_RetreiveBackupKeyGUID_2048bits(struct torture_context *tctx, > RSA *rsa; > int RSA_returned_bits; > >+ torture_assert(tctx, r != NULL, "createRetreiveBackupKeyGUIDStruct failed"); >+ > hx509_context_init(&hctx); > > if (r == NULL) { >-- >1.9.1 > > >From 5fed83c4827869ed0bdfa16bd32796f4464ab21c Mon Sep 17 00:00:00 2001 >From: Andrew Bartlett <abartlet@samba.org> >Date: Wed, 11 Feb 2015 11:45:45 +1300 >Subject: [PATCH 15/31] torture-backupkey: Assert dcerpc_bkrp_BackupKey_r call > was successful > >Signed-off-by: Andrew Bartlett <abartlet@samba.org> >--- > source4/torture/rpc/backupkey.c | 6 ++++++ > 1 file changed, 6 insertions(+) > >diff --git a/source4/torture/rpc/backupkey.c b/source4/torture/rpc/backupkey.c >index 7f5676a..8187643 100644 >--- a/source4/torture/rpc/backupkey.c >+++ b/source4/torture/rpc/backupkey.c >@@ -579,6 +579,9 @@ static struct bkrp_BackupKey *createRestoreGUIDStruct(struct torture_context *tc > > torture_assert_ntstatus_ok(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r), > "Get GUID"); >+ torture_assert_werr_ok(tctx, r->out.result, >+ "Get GUID"); >+ > /* > * We have to set it outside of the function createRetreiveBackupKeyGUIDStruct > * the len of the blob, this is due to the fact that they don't have the >@@ -1079,6 +1082,9 @@ static bool test_RetreiveBackupKeyGUID_2048bits(struct torture_context *tctx, > dcerpc_bkrp_BackupKey_r(b, tctx, r), > "Get GUID"); > >+ torture_assert_werr_ok(tctx, r->out.result, >+ "Get GUID"); >+ > out_blob.length = *r->out.data_out_len; > > hret = hx509_cert_init_data(hctx, out_blob.data, out_blob.length, &cert); >-- >1.9.1 > > >From dae5410c0aeecb92d226c0b08b922cc67bc94e2b Mon Sep 17 00:00:00 2001 >From: Garming Sam <garming@catalyst.net.nz> >Date: Thu, 5 Feb 2015 11:07:30 +1300 >Subject: [PATCH 16/31] backupkey: begin by factoring out the server wrap > functions > >--- > source4/rpc_server/backupkey/dcesrv_backupkey.c | 18 +++++++++++++++--- > 1 file changed, 15 insertions(+), 3 deletions(-) > >diff --git a/source4/rpc_server/backupkey/dcesrv_backupkey.c b/source4/rpc_server/backupkey/dcesrv_backupkey.c >index fb55875..1bcb115 100644 >--- a/source4/rpc_server/backupkey/dcesrv_backupkey.c >+++ b/source4/rpc_server/backupkey/dcesrv_backupkey.c >@@ -1224,7 +1224,7 @@ static WERROR bkrp_do_retrieve_client_wrap_key(struct dcesrv_call_state *dce_cal > */ > return WERR_FILE_NOT_FOUND; > } >- >+ > cert_secret_name = talloc_asprintf(mem_ctx, > "BCKUPKEY_%s", > guid_string); >@@ -1259,6 +1259,18 @@ static WERROR bkrp_do_retrieve_client_wrap_key(struct dcesrv_call_state *dce_cal > return WERR_NOT_SUPPORTED; > } > >+static WERROR bkrp_do_uncrypt_server_wrap_key(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, >+ struct bkrp_BackupKey *r ,struct ldb_context *ldb_ctx) >+{ >+ return WERR_NOT_SUPPORTED; >+} >+ >+static WERROR bkrp_do_retrieve_server_wrap_key(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, >+ struct bkrp_BackupKey *r ,struct ldb_context *ldb_ctx) >+{ >+ return WERR_NOT_SUPPORTED; >+} >+ > static WERROR dcesrv_bkrp_BackupKey(struct dcesrv_call_state *dce_call, > TALLOC_CTX *mem_ctx, struct bkrp_BackupKey *r) > { >@@ -1312,13 +1324,13 @@ static WERROR dcesrv_bkrp_BackupKey(struct dcesrv_call_state *dce_call, > if (strncasecmp(GUID_string(mem_ctx, r->in.guidActionAgent), > BACKUPKEY_RESTORE_GUID_WIN2K, strlen(BACKUPKEY_RESTORE_GUID_WIN2K)) == 0) { > DEBUG(debuglevel, ("Client %s requested to decrypt a server side wrapped secret, not implemented yet\n", addr)); >- return WERR_NOT_SUPPORTED; /* is this appropriate? */ >+ error = bkrp_do_uncrypt_server_wrap_key(dce_call, mem_ctx, r, ldb_ctx); > } > > if (strncasecmp(GUID_string(mem_ctx, r->in.guidActionAgent), > BACKUPKEY_BACKUP_GUID, strlen(BACKUPKEY_BACKUP_GUID)) == 0) { > DEBUG(debuglevel, ("Client %s requested a server wrapped secret, not implemented yet\n", addr)); >- return WERR_NOT_SUPPORTED; /* is this appropriate? */ >+ error = bkrp_do_retrieve_server_wrap_key(dce_call, mem_ctx, r, ldb_ctx); > } > } > /*else: I am a RODC so I don't handle backup key protocol */ >-- >1.9.1 > > >From 41a74c0591b4a26df9ce1fb38d89b666c48d3a10 Mon Sep 17 00:00:00 2001 >From: Garming Sam <garming@catalyst.net.nz> >Date: Thu, 5 Feb 2015 18:17:58 +1300 >Subject: [PATCH 17/31] backupkey: Improve IDL > >--- > librpc/idl/backupkey.idl | 14 +++++++------- > 1 file changed, 7 insertions(+), 7 deletions(-) > >diff --git a/librpc/idl/backupkey.idl b/librpc/idl/backupkey.idl >index 18098cd..76c0eb7 100644 >--- a/librpc/idl/backupkey.idl >+++ b/librpc/idl/backupkey.idl >@@ -99,19 +99,19 @@ interface backupkey > } bkrp_access_check_v3; > > [public] typedef struct { >- [subcontext(0),subcontext_size(32),flag(NDR_REMAINING)] DATA_BLOB r3; >- [subcontext(0),subcontext_size(20),flag(NDR_REMAINING)] DATA_BLOB mac; >+ uint8 r3[32]; >+ uint8 mac[20]; > dom_sid sid; >- [subcontext(0),flag(NDR_REMAINING)] DATA_BLOB secret; >+ [subcontext(0),flag(NDR_REMAINING)] DATA_BLOB secret_data; > } bkrp_rc4encryptedpayload; > > [public] typedef struct { > [value(0x00000001)] uint32 magic; > uint32 payload_length; >- uint32 cyphertext_length; >- [subcontext(0),subcontext_size(16),flag(NDR_REMAINING)] DATA_BLOB guid_of_wrapping_key; >- [subcontext(0),subcontext_size(68),flag(NDR_REMAINING)] DATA_BLOB r2; >- [subcontext(0),flag(NDR_REMAINING)] DATA_BLOB rc4encryptedpayload; >+ uint32 ciphertext_length; >+ GUID guid; >+ uint8 r2[68]; >+ uint8 rc4encryptedpayload[ciphertext_length]; > } bkrp_server_side_wrapped; > > [public] typedef struct { >-- >1.9.1 > > >From 90728cff6f3e94ab3d43e9441f112b24f3a6c7f8 Mon Sep 17 00:00:00 2001 >From: Andrew Bartlett <abartlet@samba.org> >Date: Tue, 10 Feb 2015 15:48:06 +1300 >Subject: [PATCH 18/31] backupkey: Move SID comparison to inside > get_and_verify_access_check() > >Signed-off-by: Andrew Bartlett <abartlet@samba.org> >--- > source4/rpc_server/backupkey/dcesrv_backupkey.c | 55 ++++++++++++------------- > 1 file changed, 26 insertions(+), 29 deletions(-) > >diff --git a/source4/rpc_server/backupkey/dcesrv_backupkey.c b/source4/rpc_server/backupkey/dcesrv_backupkey.c >index 1bcb115..e3310c9 100644 >--- a/source4/rpc_server/backupkey/dcesrv_backupkey.c >+++ b/source4/rpc_server/backupkey/dcesrv_backupkey.c >@@ -380,7 +380,7 @@ static WERROR get_and_verify_access_check(TALLOC_CTX *sub_ctx, > uint8_t *key_and_iv, > uint8_t *access_check, > uint32_t access_check_len, >- struct dom_sid **access_sid) >+ struct auth_session_info *session_info) > { > heim_octet_string iv; > heim_octet_string access_check_os; >@@ -393,10 +393,12 @@ static WERROR get_and_verify_access_check(TALLOC_CTX *sub_ctx, > enum ndr_err_code ndr_err; > hx509_context hctx; > >+ struct dom_sid *access_sid = NULL; >+ struct dom_sid *caller_sid = NULL; >+ > /* This one should not be freed */ > const AlgorithmIdentifier *alg; > >- *access_sid = NULL; > switch (version) { > case 2: > key_len = 24; >@@ -451,7 +453,9 @@ static WERROR get_and_verify_access_check(TALLOC_CTX *sub_ctx, > > hx509_crypto_destroy(crypto); > >- if (version == 2) { >+ switch (version) { >+ case 2: >+ { > uint32_t hash_size = 20; > uint8_t hash[hash_size]; > struct sha sctx; >@@ -483,14 +487,11 @@ static WERROR get_and_verify_access_check(TALLOC_CTX *sub_ctx, > DEBUG(2, ("Wrong hash value in the access check in backup key remote protocol\n")); > return WERR_INVALID_DATA; > } >- *access_sid = dom_sid_dup(sub_ctx, &(uncrypted_accesscheckv2.sid)); >- if (*access_sid == NULL) { >- return WERR_NOMEM; >- } >- return WERR_OK; >+ access_sid = &(uncrypted_accesscheckv2.sid); >+ break; > } >- >- if (version == 3) { >+ case 3: >+ { > uint32_t hash_size = 64; > uint8_t hash[hash_size]; > struct hc_sha512state sctx; >@@ -522,15 +523,20 @@ static WERROR get_and_verify_access_check(TALLOC_CTX *sub_ctx, > DEBUG(2, ("Wrong hash value in the access check in backup key remote protocol\n")); > return WERR_INVALID_DATA; > } >- *access_sid = dom_sid_dup(sub_ctx, &(uncrypted_accesscheckv3.sid)); >- if (*access_sid == NULL) { >- return WERR_NOMEM; >- } >- return WERR_OK; >+ access_sid = &(uncrypted_accesscheckv3.sid); >+ break; > } >- >- /* Never reached normally as we filtered at the switch / case level */ >- return WERR_INVALID_DATA; >+ default: >+ /* Never reached normally as we filtered at the switch / case level */ >+ return WERR_INVALID_DATA; >+ } >+ >+ caller_sid = &session_info->security_token->sids[PRIMARY_USER_SID_INDEX]; >+ >+ if (!dom_sid_equal(caller_sid, access_sid)) { >+ return WERR_INVALID_ACCESS; >+ } >+ return WERR_OK; > } > > static WERROR bkrp_do_uncrypt_client_wrap_key(struct dcesrv_call_state *dce_call, >@@ -599,11 +605,9 @@ static WERROR bkrp_do_uncrypt_client_wrap_key(struct dcesrv_call_state *dce_call > struct bkrp_exported_RSA_key_pair keypair; > hx509_private_key pk; > uint32_t i, res; >- struct dom_sid *access_sid = NULL; > heim_octet_string reversed_secret; > heim_octet_string uncrypted_secret; > AlgorithmIdentifier alg; >- struct dom_sid *caller_sid; > DATA_BLOB blob_us; > WERROR werr; > >@@ -669,7 +673,7 @@ static WERROR bkrp_do_uncrypt_client_wrap_key(struct dcesrv_call_state *dce_call > uncrypted_secretv2.payload_key, > uncrypt_request.access_check, > uncrypt_request.access_check_len, >- &access_sid); >+ dce_call->conn->auth_state.session_info); > if (!W_ERROR_IS_OK(werr)) { > return werr; > } >@@ -704,7 +708,7 @@ static WERROR bkrp_do_uncrypt_client_wrap_key(struct dcesrv_call_state *dce_call > uncrypted_secretv3.payload_key, > uncrypt_request.access_check, > uncrypt_request.access_check_len, >- &access_sid); >+ dce_call->conn->auth_state.session_info); > if (!W_ERROR_IS_OK(werr)) { > return werr; > } >@@ -718,13 +722,6 @@ static WERROR bkrp_do_uncrypt_client_wrap_key(struct dcesrv_call_state *dce_call > uncrypted->length = uncrypted_secretv3.secret_len; > } > >- caller_sid = &dce_call->conn->auth_state.session_info->security_token->sids[PRIMARY_USER_SID_INDEX]; >- >- if (!dom_sid_equal(caller_sid, access_sid)) { >- talloc_free(uncrypted); >- return WERR_INVALID_ACCESS; >- } >- > /* > * Yeah if we are here all looks pretty good: > * - hash is ok >-- >1.9.1 > > >From d1877a6631d17ff547b0a56d28365bc3601ceeb5 Mon Sep 17 00:00:00 2001 >From: Andrew Bartlett <abartlet@samba.org> >Date: Tue, 10 Feb 2015 15:50:15 +1300 >Subject: [PATCH 19/31] backupkey: Improve function names and comments for > clarity > >--- > source4/rpc_server/backupkey/dcesrv_backupkey.c | 42 ++++++++++++++++++++----- > 1 file changed, 34 insertions(+), 8 deletions(-) > >diff --git a/source4/rpc_server/backupkey/dcesrv_backupkey.c b/source4/rpc_server/backupkey/dcesrv_backupkey.c >index e3310c9..a6484cd 100644 >--- a/source4/rpc_server/backupkey/dcesrv_backupkey.c >+++ b/source4/rpc_server/backupkey/dcesrv_backupkey.c >@@ -539,10 +539,27 @@ static WERROR get_and_verify_access_check(TALLOC_CTX *sub_ctx, > return WERR_OK; > } > >-static WERROR bkrp_do_uncrypt_client_wrap_key(struct dcesrv_call_state *dce_call, >- TALLOC_CTX *mem_ctx, >- struct bkrp_BackupKey *r, >- struct ldb_context *ldb_ctx) >+/* >+ * We have some data, such as saved website or IMAP passwords that the >+ * client has in profile on-disk. This needs to be decrypted. This >+ * version gives the server the data over the network (protected by >+ * the X.509 certificate and public key encryption, and asks that it >+ * be decrypted returned for short-term use, protected only by the >+ * negotiated transport encryption. >+ * >+ * The data is NOT stored in the LSA, but a X.509 certificate, public >+ * and private keys used to encrypt the data will be stored. There is >+ * only one active encryption key pair and certificate per domain, it >+ * is pointed at with G$BCKUPKEY_PREFERRED in the LSA secrets store. >+ * >+ * The potentially multiple valid decrypting key pairs are in turn >+ * stored in the LSA secrets store as G$BCKUPKEY_keyGuidString. >+ * >+ */ >+static WERROR bkrp_client_wrap_decrypt_data(struct dcesrv_call_state *dce_call, >+ TALLOC_CTX *mem_ctx, >+ struct bkrp_BackupKey *r, >+ struct ldb_context *ldb_ctx) > { > struct bkrp_client_side_wrapped uncrypt_request; > DATA_BLOB blob; >@@ -704,6 +721,15 @@ static WERROR bkrp_do_uncrypt_client_wrap_key(struct dcesrv_call_state *dce_call > return WERR_INVALID_DATA; > } > >+ /* >+ * Confirm that the caller is permitted to >+ * read this particular data. Because one key >+ * pair is used per domain, the caller could >+ * have stolen the profile data on-disk and >+ * would otherwise be able to read the >+ * passwords. >+ */ >+ > werr = get_and_verify_access_check(mem_ctx, 3, > uncrypted_secretv3.payload_key, > uncrypt_request.access_check, >@@ -1158,8 +1184,8 @@ static WERROR generate_bkrp_cert(TALLOC_CTX *ctx, struct dcesrv_call_state *dce_ > return WERR_OK; > } > >-static WERROR bkrp_do_retrieve_client_wrap_key(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, >- struct bkrp_BackupKey *r ,struct ldb_context *ldb_ctx) >+static WERROR bkrp_retrieve_client_wrap_key(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, >+ struct bkrp_BackupKey *r, struct ldb_context *ldb_ctx) > { > struct GUID guid; > char *guid_string; >@@ -1309,13 +1335,13 @@ static WERROR dcesrv_bkrp_BackupKey(struct dcesrv_call_state *dce_call, > if(strncasecmp(GUID_string(mem_ctx, r->in.guidActionAgent), > BACKUPKEY_RESTORE_GUID, strlen(BACKUPKEY_RESTORE_GUID)) == 0) { > DEBUG(debuglevel, ("Client %s requested to decrypt a client side wrapped secret\n", addr)); >- error = bkrp_do_uncrypt_client_wrap_key(dce_call, mem_ctx, r, ldb_ctx); >+ error = bkrp_client_wrap_decrypt_data(dce_call, mem_ctx, r, ldb_ctx); > } > > if (strncasecmp(GUID_string(mem_ctx, r->in.guidActionAgent), > BACKUPKEY_RETRIEVE_BACKUP_KEY_GUID, strlen(BACKUPKEY_RETRIEVE_BACKUP_KEY_GUID)) == 0) { > DEBUG(debuglevel, ("Client %s requested certificate for client wrapped secret\n", addr)); >- error = bkrp_do_retrieve_client_wrap_key(dce_call, mem_ctx, r, ldb_ctx); >+ error = bkrp_retrieve_client_wrap_key(dce_call, mem_ctx, r, ldb_ctx); > } > > if (strncasecmp(GUID_string(mem_ctx, r->in.guidActionAgent), >-- >1.9.1 > > >From bcc2d179e6446711dc3231842f2c22a613d87f35 Mon Sep 17 00:00:00 2001 >From: Andrew Bartlett <abartlet@samba.org> >Date: Tue, 10 Feb 2015 16:02:00 +1300 >Subject: [PATCH 20/31] backupkey: Implement ServerWrap Encrypt protocol > >BUG: https://bugzilla.samba.org/attachment.cgi?bugid=11097 > >Signed-off-by: Andrew Bartlett <abartlet@samba.org> >--- > source4/rpc_server/backupkey/dcesrv_backupkey.c | 312 +++++++++++++++++++++++- > 1 file changed, 299 insertions(+), 13 deletions(-) > >diff --git a/source4/rpc_server/backupkey/dcesrv_backupkey.c b/source4/rpc_server/backupkey/dcesrv_backupkey.c >index a6484cd..e7fb3d4 100644 >--- a/source4/rpc_server/backupkey/dcesrv_backupkey.c >+++ b/source4/rpc_server/backupkey/dcesrv_backupkey.c >@@ -34,9 +34,13 @@ > #include <hcrypto/rsa.h> > #include <hcrypto/bn.h> > #include <hcrypto/sha.h> >+#include <hcrypto/evp.h> >+#include <hcrypto/hmac.h> > #include <der.h> > #include "../lib/tsocket/tsocket.h" > #include "../libcli/security/security.h" >+#include "librpc/gen_ndr/ndr_security.h" >+#include "lib/crypto/arcfour.h" > > #define BACKUPKEY_MIN_VERSION 2 > #define BACKUPKEY_MAX_VERSION 3 >@@ -1271,29 +1275,311 @@ static WERROR bkrp_retrieve_client_wrap_key(struct dcesrv_call_state *dce_call, > W_ERROR_HAVE_NO_MEMORY(*(r->out.data_out)); > return WERR_OK; > } else { >- DEBUG(10, ("No or broken secret called %s\n", cert_secret_name)); >- return WERR_FILE_NOT_FOUND; >+ DEBUG(1, ("No or broken secret called %s\n", cert_secret_name)); >+ return WERR_INTERNAL_ERROR; > } >- } else { >- DEBUG(10, ("No secret BCKUPKEY_PREFERRED\n")); >- return WERR_FILE_NOT_FOUND; > } > > return WERR_NOT_SUPPORTED; > } > >-static WERROR bkrp_do_uncrypt_server_wrap_key(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, >- struct bkrp_BackupKey *r ,struct ldb_context *ldb_ctx) >+static WERROR generate_bkrp_server_wrap_key(TALLOC_CTX *ctx, struct ldb_context *ldb_ctx) > { >- return WERR_NOT_SUPPORTED; >+ struct GUID guid = GUID_random(); >+ enum ndr_err_code ndr_err; >+ DATA_BLOB blob_wrap_key, guid_blob; >+ struct bkrp_dc_serverwrap_key wrap_key; >+ NTSTATUS status; >+ char *secret_name; >+ TALLOC_CTX *frame = talloc_stackframe(); >+ >+ generate_random_buffer(wrap_key.key, sizeof(wrap_key.key)); >+ >+ ndr_err = ndr_push_struct_blob(&blob_wrap_key, ctx, &wrap_key, (ndr_push_flags_fn_t)ndr_push_bkrp_dc_serverwrap_key); >+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { >+ TALLOC_FREE(frame); >+ return WERR_INVALID_DATA; >+ } >+ >+ secret_name = talloc_asprintf(frame, "BCKUPKEY_%s", GUID_string(ctx, &guid)); >+ if (secret_name == NULL) { >+ TALLOC_FREE(frame); >+ return WERR_NOMEM; >+ } >+ >+ status = set_lsa_secret(frame, ldb_ctx, secret_name, &blob_wrap_key); >+ if (!NT_STATUS_IS_OK(status)) { >+ DEBUG(2, ("Failed to save the secret %s\n", secret_name)); >+ TALLOC_FREE(frame); >+ return WERR_INTERNAL_ERROR; >+ } >+ >+ status = GUID_to_ndr_blob(&guid, frame, &guid_blob); >+ if (!NT_STATUS_IS_OK(status)) { >+ DEBUG(2, ("Failed to save the secret %s\n", secret_name)); >+ TALLOC_FREE(frame); >+ } >+ >+ status = set_lsa_secret(frame, ldb_ctx, "BCKUPKEY_P", &guid_blob); >+ if (!NT_STATUS_IS_OK(status)) { >+ DEBUG(2, ("Failed to save the secret %s\n", secret_name)); >+ TALLOC_FREE(frame); >+ return WERR_INTERNAL_ERROR; >+ } >+ >+ TALLOC_FREE(frame); >+ >+ return WERR_OK; > } > >-static WERROR bkrp_do_retrieve_server_wrap_key(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, >- struct bkrp_BackupKey *r ,struct ldb_context *ldb_ctx) >+static WERROR bkrp_server_wrap_decrypt_data(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, >+ struct bkrp_BackupKey *r ,struct ldb_context *ldb_ctx) > { >+ struct bkrp_server_side_wrapped uncrypt_request; >+ DATA_BLOB blob; >+ enum ndr_err_code ndr_err; >+ >+ blob.data = r->in.data_in; >+ blob.length = r->in.data_in_len; >+ >+ if (r->in.data_in_len == 0 || r->in.data_in == NULL) { >+ return WERR_INVALID_PARAM; >+ } >+ >+ ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &uncrypt_request, >+ (ndr_pull_flags_fn_t)ndr_pull_bkrp_server_side_wrapped); >+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { >+ return WERR_INVALID_PARAM; >+ } >+ > return WERR_NOT_SUPPORTED; > } > >+/* >+ * Find the current, preferred ServerWrap Key by looking at >+ * G$BCKUPKEY_P in the LSA secrets store. >+ * >+ * Then find the current decryption keys from the LSA secrets store as >+ * G$BCKUPKEY_keyGuidString. >+ */ >+ >+static WERROR bkrp_do_retrieve_server_wrap_key(TALLOC_CTX *mem_ctx, struct ldb_context *ldb_ctx, >+ struct bkrp_dc_serverwrap_key *server_key, >+ struct GUID *guid) >+{ >+ NTSTATUS status; >+ DATA_BLOB guid_binary, lsa_secret; >+ char *secret_name; >+ char *guid_string; >+ enum ndr_err_code ndr_err; >+ >+ status = get_lsa_secret(mem_ctx, ldb_ctx, "BCKUPKEY_P", &guid_binary); >+ if (!NT_STATUS_IS_OK(status)) { >+ DEBUG(10, ("Error while fetching secret BCKUPKEY_P to find current GUID\n")); >+ return WERR_FILE_NOT_FOUND; >+ } else if (guid_binary.length == 0) { >+ /* RODC case, we do not have secrets locally */ >+ DEBUG(1, ("Unable to fetch value for secret BCKUPKEY_P, are we an undetected RODC?\n")); >+ return WERR_INTERNAL_ERROR; >+ } >+ >+ status = GUID_from_ndr_blob(&guid_binary, guid); >+ if (!NT_STATUS_IS_OK(status)) { >+ return WERR_FILE_NOT_FOUND; >+ } >+ >+ guid_string = GUID_string(mem_ctx, guid); >+ if (guid_string == NULL) { >+ /* We return file not found because the client >+ * expect this error >+ */ >+ return WERR_FILE_NOT_FOUND; >+ } >+ >+ secret_name = talloc_asprintf(mem_ctx, "BCKUPKEY_%s", guid_string); >+ if (secret_name == NULL) { >+ return WERR_NOMEM; >+ } >+ >+ status = get_lsa_secret(mem_ctx, ldb_ctx, secret_name, &lsa_secret); >+ if (!NT_STATUS_IS_OK(status)) { >+ DEBUG(10, ("Error while fetching secret %s\n", secret_name)); >+ return WERR_FILE_NOT_FOUND; >+ } else if (guid_binary.length == 0) { >+ /* RODC case, we do not have secrets locally */ >+ DEBUG(1, ("Unable to fetch value for secret %s, are we an undetected RODC?\n", >+ secret_name)); >+ return WERR_INTERNAL_ERROR; >+ } >+ ndr_err = ndr_pull_struct_blob(&lsa_secret, mem_ctx, server_key, >+ (ndr_pull_flags_fn_t)ndr_pull_bkrp_dc_serverwrap_key); >+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { >+ DEBUG(2, ("Unable to parse the ndr encoded server wrap key %s\n", secret_name)); >+ return WERR_FILE_NOT_FOUND; >+ } >+ >+ return WERR_OK; >+} >+ >+/* >+ * We have some data, such as saved website or IMAP passwords that the >+ * client would like to put into the profile on-disk. This needs to >+ * be encrypted. This version gives the server the data over the >+ * network (protected only by the negotiated transport encryption), >+ * and asks that it be encrypted and returned for long-term storage. >+ * >+ * The data is NOT stored in the LSA, but a key to encrypt the data >+ * will be stored. There is only one active encryption key per domain, >+ * it is pointed at with G$BCKUPKEY_P in the LSA secrets store. >+ * >+ * The potentially multiple valid decryptiong keys (and the encryption >+ * key) are in turn stored in the LSA secrets store as >+ * G$BCKUPKEY_keyGuidString. >+ * >+ */ >+ >+static WERROR bkrp_server_wrap_encrypt_data(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, >+ struct bkrp_BackupKey *r ,struct ldb_context *ldb_ctx) >+{ >+ DATA_BLOB sid_blob, encrypted_blob, symkey_blob, server_wrapped_blob; >+ WERROR werr; >+ struct dom_sid *caller_sid; >+ uint8_t symkey[20]; /* SHA-1 hash len */ >+ uint8_t mackey[20]; /* SHA-1 hash len */ >+ unsigned int hash_len; >+ struct bkrp_rc4encryptedpayload rc4payload; >+ HMAC_CTX ctx; >+ struct bkrp_dc_serverwrap_key server_key; >+ enum ndr_err_code ndr_err; >+ struct bkrp_server_side_wrapped server_side_wrapped; >+ struct GUID guid; >+ >+ if (r->in.data_in_len == 0 || r->in.data_in == NULL) { >+ return WERR_INVALID_PARAM; >+ } >+ >+ werr = bkrp_do_retrieve_server_wrap_key(mem_ctx, >+ ldb_ctx, &server_key, >+ &guid); >+ >+ if (!W_ERROR_IS_OK(werr)) { >+ if (W_ERROR_EQUAL(werr, WERR_FILE_NOT_FOUND)) { >+ /* Generate the server wrap key since one wasn't found */ >+ werr = generate_bkrp_server_wrap_key(mem_ctx, >+ ldb_ctx); >+ if (!W_ERROR_IS_OK(werr)) { >+ return WERR_INVALID_PARAMETER; >+ } >+ werr = bkrp_do_retrieve_server_wrap_key(mem_ctx, >+ ldb_ctx, &server_key, &guid); >+ >+ if (W_ERROR_EQUAL(werr, WERR_FILE_NOT_FOUND)) { >+ /* Ok we really don't manage to get this secret ...*/ >+ return WERR_FILE_NOT_FOUND; >+ } >+ } else { >+ /* In theory we should NEVER reach this point as it >+ should only appear in a rodc server */ >+ /* we do not have the real secret attribute */ >+ return WERR_INVALID_PARAMETER; >+ } >+ } >+ >+ caller_sid = &dce_call->conn->auth_state.session_info->security_token->sids[PRIMARY_USER_SID_INDEX]; >+ >+ dump_data_pw("server_key: \n", server_key.key, sizeof(server_key.key)); >+ >+ /* >+ * This is the key derivation step, so that the HMAC and RC4 >+ * operations over the user-supplied data are not able to >+ * disclose the master key. By using random data, the symkey >+ * and mackey values are unique for this operation, and >+ * discovering these (by reversing the RC4 over the >+ * attacker-controlled data) does not return something able to >+ * be used to decyrpt the encrypted data of other users >+ */ >+ generate_random_buffer(server_side_wrapped.r2, sizeof(server_side_wrapped.r2)); >+ >+ dump_data_pw("r2: \n", server_side_wrapped.r2, sizeof(server_side_wrapped.r2)); >+ >+ generate_random_buffer(rc4payload.r3, sizeof(rc4payload.r3)); >+ >+ dump_data_pw("r3: \n", rc4payload.r3, sizeof(rc4payload.r3)); >+ >+ >+ /* >+ * This is *not* the leading 64 bytes, as indicated in MS-BKRP 3.1.4.1.1 >+ * BACKUPKEY_BACKUP_GUID, it really is the whole key >+ */ >+ HMAC(EVP_sha1(), server_key.key, sizeof(server_key.key), >+ server_side_wrapped.r2, sizeof(server_side_wrapped.r2), >+ symkey, &hash_len); >+ >+ dump_data_pw("symkey: \n", symkey, hash_len); >+ >+ /* >+ * This is *not* the leading 64 bytes, as indicated in MS-BKRP 3.1.4.1.1 >+ * BACKUPKEY_BACKUP_GUID, it really is the whole key >+ */ >+ HMAC(EVP_sha1(), server_key.key, sizeof(server_key.key), >+ rc4payload.r3, sizeof(rc4payload.r3), >+ mackey, &hash_len); >+ >+ dump_data_pw("mackey: \n", mackey, sizeof(mackey)); >+ >+ ndr_err = ndr_push_struct_blob(&sid_blob, mem_ctx, caller_sid, >+ (ndr_push_flags_fn_t)ndr_push_dom_sid); >+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { >+ return WERR_INTERNAL_ERROR; >+ } >+ >+ rc4payload.secret_data.data = r->in.data_in; >+ rc4payload.secret_data.length = r->in.data_in_len; >+ >+ >+ HMAC_CTX_init(&ctx); >+ HMAC_Init_ex(&ctx, mackey, 20, EVP_sha1(), NULL); >+ /* SID field */ >+ HMAC_Update(&ctx, sid_blob.data, sid_blob.length); >+ /* Secret field */ >+ HMAC_Update(&ctx, rc4payload.secret_data.data, rc4payload.secret_data.length); >+ HMAC_Final(&ctx, rc4payload.mac, &hash_len); >+ HMAC_CTX_cleanup(&ctx); >+ >+ dump_data_pw("rc4payload.mac: \n", rc4payload.mac, sizeof(rc4payload.mac)); >+ >+ rc4payload.sid = *caller_sid; >+ >+ ndr_err = ndr_push_struct_blob(&encrypted_blob, mem_ctx, &rc4payload, >+ (ndr_push_flags_fn_t)ndr_push_bkrp_rc4encryptedpayload); >+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { >+ return WERR_INTERNAL_ERROR; >+ } >+ >+ /* rc4 encrypt sid and secret using sym key */ >+ symkey_blob = data_blob_const(symkey, sizeof(symkey)); >+ arcfour_crypt_blob(encrypted_blob.data, encrypted_blob.length, &symkey_blob); >+ >+ /* create server wrap structure */ >+ >+ server_side_wrapped.payload_length = rc4payload.secret_data.length; >+ server_side_wrapped.ciphertext_length = encrypted_blob.length; >+ server_side_wrapped.guid = guid; >+ server_side_wrapped.rc4encryptedpayload = encrypted_blob.data; >+ >+ ndr_err = ndr_push_struct_blob(&server_wrapped_blob, mem_ctx, &server_side_wrapped, >+ (ndr_push_flags_fn_t)ndr_push_bkrp_server_side_wrapped); >+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { >+ return WERR_INTERNAL_ERROR; >+ } >+ >+ >+ *(r->out.data_out) = server_wrapped_blob.data; >+ *(r->out.data_out_len) = server_wrapped_blob.length; >+ >+ return WERR_OK; >+} >+ > static WERROR dcesrv_bkrp_BackupKey(struct dcesrv_call_state *dce_call, > TALLOC_CTX *mem_ctx, struct bkrp_BackupKey *r) > { >@@ -1347,13 +1633,13 @@ static WERROR dcesrv_bkrp_BackupKey(struct dcesrv_call_state *dce_call, > if (strncasecmp(GUID_string(mem_ctx, r->in.guidActionAgent), > BACKUPKEY_RESTORE_GUID_WIN2K, strlen(BACKUPKEY_RESTORE_GUID_WIN2K)) == 0) { > DEBUG(debuglevel, ("Client %s requested to decrypt a server side wrapped secret, not implemented yet\n", addr)); >- error = bkrp_do_uncrypt_server_wrap_key(dce_call, mem_ctx, r, ldb_ctx); >+ error = bkrp_server_wrap_decrypt_data(dce_call, mem_ctx, r, ldb_ctx); > } > > if (strncasecmp(GUID_string(mem_ctx, r->in.guidActionAgent), > BACKUPKEY_BACKUP_GUID, strlen(BACKUPKEY_BACKUP_GUID)) == 0) { >- DEBUG(debuglevel, ("Client %s requested a server wrapped secret, not implemented yet\n", addr)); >- error = bkrp_do_retrieve_server_wrap_key(dce_call, mem_ctx, r, ldb_ctx); >+ DEBUG(debuglevel, ("Client %s requested a server wrapped secret\n", addr)); >+ error = bkrp_server_wrap_encrypt_data(dce_call, mem_ctx, r, ldb_ctx); > } > } > /*else: I am a RODC so I don't handle backup key protocol */ >-- >1.9.1 > > >From d4bc76676114208d13eede67c6260a33376fb5f6 Mon Sep 17 00:00:00 2001 >From: Andrew Bartlett <abartlet@samba.org> >Date: Tue, 10 Feb 2015 16:16:20 +1300 >Subject: [PATCH 21/31] backupkey: Use the name lsa_secret rather than just > secret > >This makes it clear that this is the data stored on the LSA secrets store >and not the client-provided data to be encrypted. > >Signed-off-by: Andrew Bartlett <abartlet@samba.org> >--- > source4/rpc_server/backupkey/dcesrv_backupkey.c | 40 ++++++++++++------------- > 1 file changed, 20 insertions(+), 20 deletions(-) > >diff --git a/source4/rpc_server/backupkey/dcesrv_backupkey.c b/source4/rpc_server/backupkey/dcesrv_backupkey.c >index e7fb3d4..8c8e036 100644 >--- a/source4/rpc_server/backupkey/dcesrv_backupkey.c >+++ b/source4/rpc_server/backupkey/dcesrv_backupkey.c >@@ -54,7 +54,7 @@ static const AlgorithmIdentifier _hx509_signature_rsa_with_var_num = { > static NTSTATUS set_lsa_secret(TALLOC_CTX *mem_ctx, > struct ldb_context *ldb, > const char *name, >- const DATA_BLOB *secret) >+ const DATA_BLOB *lsa_secret) > { > struct ldb_message *msg; > struct ldb_result *res; >@@ -141,8 +141,8 @@ static NTSTATUS set_lsa_secret(TALLOC_CTX *mem_ctx, > talloc_free(msg); > return NT_STATUS_NO_MEMORY; > } >- val.data = secret->data; >- val.length = secret->length; >+ val.data = lsa_secret->data; >+ val.length = lsa_secret->length; > ret = ldb_msg_add_value(msg, "currentValue", &val, NULL); > if (ret != LDB_SUCCESS) { > talloc_free(msg); >@@ -176,7 +176,7 @@ static NTSTATUS set_lsa_secret(TALLOC_CTX *mem_ctx, > static NTSTATUS get_lsa_secret(TALLOC_CTX *mem_ctx, > struct ldb_context *ldb, > const char *name, >- DATA_BLOB *secret) >+ DATA_BLOB *lsa_secret) > { > TALLOC_CTX *tmp_mem; > struct ldb_result *res; >@@ -190,8 +190,8 @@ static NTSTATUS get_lsa_secret(TALLOC_CTX *mem_ctx, > }; > int ret; > >- secret->data = NULL; >- secret->length = 0; >+ lsa_secret->data = NULL; >+ lsa_secret->length = 0; > > domain_dn = ldb_get_default_basedn(ldb); > if (!domain_dn) { >@@ -241,8 +241,8 @@ static NTSTATUS get_lsa_secret(TALLOC_CTX *mem_ctx, > } > > data = val->data; >- secret->data = talloc_move(mem_ctx, &data); >- secret->length = val->length; >+ lsa_secret->data = talloc_move(mem_ctx, &data); >+ lsa_secret->length = val->length; > > talloc_free(tmp_mem); > return NT_STATUS_OK; >@@ -570,7 +570,7 @@ static WERROR bkrp_client_wrap_decrypt_data(struct dcesrv_call_state *dce_call, > enum ndr_err_code ndr_err; > char *guid_string; > char *cert_secret_name; >- DATA_BLOB secret; >+ DATA_BLOB lsa_secret; > DATA_BLOB *uncrypted; > NTSTATUS status; > >@@ -610,7 +610,7 @@ static WERROR bkrp_client_wrap_decrypt_data(struct dcesrv_call_state *dce_call, > status = get_lsa_secret(mem_ctx, > ldb_ctx, > cert_secret_name, >- &secret); >+ &lsa_secret); > if (!NT_STATUS_IS_OK(status)) { > DEBUG(10, ("Error while fetching secret %s\n", cert_secret_name)); > if (NT_STATUS_EQUAL(status,NT_STATUS_OBJECT_NAME_NOT_FOUND)) { >@@ -621,7 +621,7 @@ static WERROR bkrp_client_wrap_decrypt_data(struct dcesrv_call_state *dce_call, > } > } > >- if (secret.length != 0) { >+ if (lsa_secret.length != 0) { > hx509_context hctx; > struct bkrp_exported_RSA_key_pair keypair; > hx509_private_key pk; >@@ -632,7 +632,7 @@ static WERROR bkrp_client_wrap_decrypt_data(struct dcesrv_call_state *dce_call, > DATA_BLOB blob_us; > WERROR werr; > >- ndr_err = ndr_pull_struct_blob(&secret, mem_ctx, &keypair, (ndr_pull_flags_fn_t)ndr_pull_bkrp_exported_RSA_key_pair); >+ ndr_err = ndr_pull_struct_blob(&lsa_secret, mem_ctx, &keypair, (ndr_pull_flags_fn_t)ndr_pull_bkrp_exported_RSA_key_pair); > if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { > DEBUG(2, ("Unable to parse the ndr encoded cert in key %s\n", cert_secret_name)); > return WERR_FILE_NOT_FOUND; >@@ -1193,7 +1193,7 @@ static WERROR bkrp_retrieve_client_wrap_key(struct dcesrv_call_state *dce_call, > { > struct GUID guid; > char *guid_string; >- DATA_BLOB secret; >+ DATA_BLOB lsa_secret; > enum ndr_err_code ndr_err; > NTSTATUS status; > >@@ -1205,7 +1205,7 @@ static WERROR bkrp_retrieve_client_wrap_key(struct dcesrv_call_state *dce_call, > status = get_lsa_secret(mem_ctx, > ldb_ctx, > "BCKUPKEY_PREFERRED", >- &secret); >+ &lsa_secret); > if (!NT_STATUS_IS_OK(status)) { > DEBUG(10, ("Error while fetching secret BCKUPKEY_PREFERRED\n")); > if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { >@@ -1221,7 +1221,7 @@ static WERROR bkrp_retrieve_client_wrap_key(struct dcesrv_call_state *dce_call, > status = get_lsa_secret(mem_ctx, > ldb_ctx, > "BCKUPKEY_PREFERRED", >- &secret); >+ &lsa_secret); > > if (!NT_STATUS_IS_OK(status)) { > /* Ok we really don't manage to get this certs ...*/ >@@ -1236,10 +1236,10 @@ static WERROR bkrp_retrieve_client_wrap_key(struct dcesrv_call_state *dce_call, > } > } > >- if (secret.length != 0) { >+ if (lsa_secret.length != 0) { > char *cert_secret_name; > >- status = GUID_from_ndr_blob(&secret, &guid); >+ status = GUID_from_ndr_blob(&lsa_secret, &guid); > if (!NT_STATUS_IS_OK(status)) { > return WERR_FILE_NOT_FOUND; > } >@@ -1258,14 +1258,14 @@ static WERROR bkrp_retrieve_client_wrap_key(struct dcesrv_call_state *dce_call, > status = get_lsa_secret(mem_ctx, > ldb_ctx, > cert_secret_name, >- &secret); >+ &lsa_secret); > if (!NT_STATUS_IS_OK(status)) { > return WERR_FILE_NOT_FOUND; > } > >- if (secret.length != 0) { >+ if (lsa_secret.length != 0) { > struct bkrp_exported_RSA_key_pair keypair; >- ndr_err = ndr_pull_struct_blob(&secret, mem_ctx, &keypair, >+ ndr_err = ndr_pull_struct_blob(&lsa_secret, mem_ctx, &keypair, > (ndr_pull_flags_fn_t)ndr_pull_bkrp_exported_RSA_key_pair); > if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { > return WERR_FILE_NOT_FOUND; >-- >1.9.1 > > >From ee87aaadb0bbc28b1f035d62faeccaffbac89f68 Mon Sep 17 00:00:00 2001 >From: Andrew Bartlett <abartlet@samba.org> >Date: Tue, 10 Feb 2015 16:23:17 +1300 >Subject: [PATCH 22/31] backupkey: Improve variable names to make clear this is > client-provided data > >The values we return here are client-provided passwords or other keys, that we decrypt for them. > >Signed-off-by: Andrew Bartlett <abartlet@samba.org> >--- > source4/rpc_server/backupkey/dcesrv_backupkey.c | 26 ++++++++++++------------- > 1 file changed, 13 insertions(+), 13 deletions(-) > >diff --git a/source4/rpc_server/backupkey/dcesrv_backupkey.c b/source4/rpc_server/backupkey/dcesrv_backupkey.c >index 8c8e036..7200e16 100644 >--- a/source4/rpc_server/backupkey/dcesrv_backupkey.c >+++ b/source4/rpc_server/backupkey/dcesrv_backupkey.c >@@ -571,7 +571,7 @@ static WERROR bkrp_client_wrap_decrypt_data(struct dcesrv_call_state *dce_call, > char *guid_string; > char *cert_secret_name; > DATA_BLOB lsa_secret; >- DATA_BLOB *uncrypted; >+ DATA_BLOB *uncrypted_data; > NTSTATUS status; > > blob.data = r->in.data_in; >@@ -698,13 +698,13 @@ static WERROR bkrp_client_wrap_decrypt_data(struct dcesrv_call_state *dce_call, > if (!W_ERROR_IS_OK(werr)) { > return werr; > } >- uncrypted = talloc(mem_ctx, DATA_BLOB); >- if (uncrypted == NULL) { >+ uncrypted_data = talloc(mem_ctx, DATA_BLOB); >+ if (uncrypted_data == NULL) { > return WERR_INVALID_DATA; > } > >- uncrypted->data = uncrypted_secretv2.secret; >- uncrypted->length = uncrypted_secretv2.secret_len; >+ uncrypted_data->data = uncrypted_secretv2.secret; >+ uncrypted_data->length = uncrypted_secretv2.secret_len; > } > if (uncrypt_request.version == 3) { > struct bkrp_encrypted_secret_v3 uncrypted_secretv3; >@@ -743,13 +743,13 @@ static WERROR bkrp_client_wrap_decrypt_data(struct dcesrv_call_state *dce_call, > return werr; > } > >- uncrypted = talloc(mem_ctx, DATA_BLOB); >- if (uncrypted == NULL) { >+ uncrypted_data = talloc(mem_ctx, DATA_BLOB); >+ if (uncrypted_data == NULL) { > return WERR_INVALID_DATA; > } > >- uncrypted->data = uncrypted_secretv3.secret; >- uncrypted->length = uncrypted_secretv3.secret_len; >+ uncrypted_data->data = uncrypted_secretv3.secret; >+ uncrypted_data->length = uncrypted_secretv3.secret_len; > } > > /* >@@ -760,7 +760,7 @@ static WERROR bkrp_client_wrap_decrypt_data(struct dcesrv_call_state *dce_call, > */ > } > >- if (uncrypted->data == NULL) { >+ if (uncrypted_data->data == NULL) { > return WERR_INVALID_DATA; > } > >@@ -769,10 +769,10 @@ static WERROR bkrp_client_wrap_decrypt_data(struct dcesrv_call_state *dce_call, > * parent structure is just an array of bytes it a lot of work > * work just prepending 4 bytes > */ >- *(r->out.data_out) = talloc_zero_array(mem_ctx, uint8_t, uncrypted->length + 4); >+ *(r->out.data_out) = talloc_zero_array(mem_ctx, uint8_t, uncrypted_data->length + 4); > W_ERROR_HAVE_NO_MEMORY(*(r->out.data_out)); >- memcpy(4+*(r->out.data_out), uncrypted->data, uncrypted->length); >- *(r->out.data_out_len) = uncrypted->length + 4; >+ memcpy(4+*(r->out.data_out), uncrypted_data->data, uncrypted_data->length); >+ *(r->out.data_out_len) = uncrypted_data->length + 4; > > return WERR_OK; > } >-- >1.9.1 > > >From 731cf24940fd0cc70555c734c27f31458fa7545e Mon Sep 17 00:00:00 2001 >From: Andrew Bartlett <abartlet@samba.org> >Date: Tue, 10 Feb 2015 16:26:23 +1300 >Subject: [PATCH 23/31] backupkey: Handle more clearly the case where we find > the secret, but it has no value > >This happen on the RODC, a case that we try not to permit at all. >--- > source4/rpc_server/backupkey/dcesrv_backupkey.c | 78 +++++++++++-------------- > 1 file changed, 33 insertions(+), 45 deletions(-) > >diff --git a/source4/rpc_server/backupkey/dcesrv_backupkey.c b/source4/rpc_server/backupkey/dcesrv_backupkey.c >index 7200e16..70925dc 100644 >--- a/source4/rpc_server/backupkey/dcesrv_backupkey.c >+++ b/source4/rpc_server/backupkey/dcesrv_backupkey.c >@@ -213,18 +213,12 @@ static NTSTATUS get_lsa_secret(TALLOC_CTX *mem_ctx, > "(&(cn=%s Secret)(objectclass=secret))", > ldb_binary_encode_string(tmp_mem, name)); > >- if (ret != LDB_SUCCESS || res->count == 0) { >+ if (ret != LDB_SUCCESS) { > talloc_free(tmp_mem); >- /* >- * Important NOT to use NT_STATUS_OBJECT_NAME_NOT_FOUND >- * as this return value is used to detect the case >- * when we have the secret but without the currentValue >- * (case RODC) >- */ >+ return NT_STATUS_INTERNAL_DB_CORRUPTION; >+ } else if (res->count == 0) { > return NT_STATUS_RESOURCE_NAME_NOT_FOUND; >- } >- >- if (res->count > 1) { >+ } else if (res->count > 1) { > DEBUG(2, ("Secret %s collision\n", name)); > talloc_free(tmp_mem); > return NT_STATUS_INTERNAL_DB_CORRUPTION; >@@ -236,8 +230,9 @@ static NTSTATUS get_lsa_secret(TALLOC_CTX *mem_ctx, > * The secret object is here but we don't have the secret value > * The most common case is a RODC > */ >+ *lsa_secret = data_blob_null; > talloc_free(tmp_mem); >- return NT_STATUS_OBJECT_NAME_NOT_FOUND; >+ return NT_STATUS_OK; > } > > data = val->data; >@@ -613,15 +608,11 @@ static WERROR bkrp_client_wrap_decrypt_data(struct dcesrv_call_state *dce_call, > &lsa_secret); > if (!NT_STATUS_IS_OK(status)) { > DEBUG(10, ("Error while fetching secret %s\n", cert_secret_name)); >- if (NT_STATUS_EQUAL(status,NT_STATUS_OBJECT_NAME_NOT_FOUND)) { >- /* we do not have the real secret attribute */ >- return WERR_INVALID_PARAMETER; >- } else { >- return WERR_FILE_NOT_FOUND; >- } >- } >- >- if (lsa_secret.length != 0) { >+ return WERR_FILE_NOT_FOUND; >+ } else if (lsa_secret.length == 0) { >+ /* we do not have the real secret attribute, like if we are an RODC */ >+ return WERR_INVALID_PARAMETER; >+ } else { > hx509_context hctx; > struct bkrp_exported_RSA_key_pair keypair; > hx509_private_key pk; >@@ -1206,37 +1197,34 @@ static WERROR bkrp_retrieve_client_wrap_key(struct dcesrv_call_state *dce_call, > ldb_ctx, > "BCKUPKEY_PREFERRED", > &lsa_secret); >- if (!NT_STATUS_IS_OK(status)) { >- DEBUG(10, ("Error while fetching secret BCKUPKEY_PREFERRED\n")); >- if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { >- /* Ok we can be in this case if there was no certs */ >- struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx; >- char *dn = talloc_asprintf(mem_ctx, "CN=%s", >- lpcfg_realm(lp_ctx)); >- >- WERROR werr = generate_bkrp_cert(mem_ctx, dce_call, ldb_ctx, dn); >- if (!W_ERROR_IS_OK(werr)) { >- return WERR_INVALID_PARAMETER; >- } >- status = get_lsa_secret(mem_ctx, >+ if (NT_STATUS_EQUAL(status, NT_STATUS_RESOURCE_NAME_NOT_FOUND)) { >+ /* Ok we can be in this case if there was no certs */ >+ struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx; >+ char *dn = talloc_asprintf(mem_ctx, "CN=%s", >+ lpcfg_realm(lp_ctx)); >+ >+ WERROR werr = generate_bkrp_cert(mem_ctx, dce_call, ldb_ctx, dn); >+ if (!W_ERROR_IS_OK(werr)) { >+ return WERR_INVALID_PARAMETER; >+ } >+ status = get_lsa_secret(mem_ctx, > ldb_ctx, > "BCKUPKEY_PREFERRED", > &lsa_secret); >- >- if (!NT_STATUS_IS_OK(status)) { >- /* Ok we really don't manage to get this certs ...*/ >- DEBUG(2, ("Unable to locate BCKUPKEY_PREFERRED after cert generation\n")); >- return WERR_FILE_NOT_FOUND; >- } >- } else { >- /* In theory we should NEVER reach this point as it >- should only appear in a rodc server */ >- /* we do not have the real secret attribute */ >- return WERR_INVALID_PARAMETER; >+ >+ if (!NT_STATUS_IS_OK(status)) { >+ /* Ok we really don't manage to get this certs ...*/ >+ DEBUG(2, ("Unable to locate BCKUPKEY_PREFERRED after cert generation\n")); >+ return WERR_FILE_NOT_FOUND; > } >+ } else if (!NT_STATUS_IS_OK(status)) { >+ return WERR_INTERNAL_ERROR; > } > >- if (lsa_secret.length != 0) { >+ if (lsa_secret.length == 0) { >+ DEBUG(1, ("No secret in BCKUPKEY_PREFERRED, are we an undetected RODC?\n")); >+ return WERR_INTERNAL_ERROR; >+ } else { > char *cert_secret_name; > > status = GUID_from_ndr_blob(&lsa_secret, &guid); >-- >1.9.1 > > >From e2d223f17c20b53eb01ac35931752425608d3201 Mon Sep 17 00:00:00 2001 >From: Andrew Bartlett <abartlet@samba.org> >Date: Wed, 11 Feb 2015 09:53:58 +1300 >Subject: [PATCH 24/31] backupkey: Implement ServerWrap Decrypt > >We implement both modes in BACKUPKEY_RESTORE_GUID, as it may decrypt >both ServerWrap and ClientWrap data, and we implement >BACKUPKEY_RESTORE_GUID_WIN2K. > >BUG: https://bugzilla.samba.org/attachment.cgi?bugid=11097 > >Signed-off-by: Andrew Bartlett <abartlet@samba.org> >--- > source4/rpc_server/backupkey/dcesrv_backupkey.c | 237 +++++++++++++++++++----- > 1 file changed, 186 insertions(+), 51 deletions(-) > >diff --git a/source4/rpc_server/backupkey/dcesrv_backupkey.c b/source4/rpc_server/backupkey/dcesrv_backupkey.c >index 70925dc..4c9115c 100644 >--- a/source4/rpc_server/backupkey/dcesrv_backupkey.c >+++ b/source4/rpc_server/backupkey/dcesrv_backupkey.c >@@ -1320,34 +1320,8 @@ static WERROR generate_bkrp_server_wrap_key(TALLOC_CTX *ctx, struct ldb_context > return WERR_OK; > } > >-static WERROR bkrp_server_wrap_decrypt_data(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, >- struct bkrp_BackupKey *r ,struct ldb_context *ldb_ctx) >-{ >- struct bkrp_server_side_wrapped uncrypt_request; >- DATA_BLOB blob; >- enum ndr_err_code ndr_err; >- >- blob.data = r->in.data_in; >- blob.length = r->in.data_in_len; >- >- if (r->in.data_in_len == 0 || r->in.data_in == NULL) { >- return WERR_INVALID_PARAM; >- } >- >- ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &uncrypt_request, >- (ndr_pull_flags_fn_t)ndr_pull_bkrp_server_side_wrapped); >- if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { >- return WERR_INVALID_PARAM; >- } >- >- return WERR_NOT_SUPPORTED; >-} >- > /* >- * Find the current, preferred ServerWrap Key by looking at >- * G$BCKUPKEY_P in the LSA secrets store. >- * >- * Then find the current decryption keys from the LSA secrets store as >+ * Find the specified decryption keys from the LSA secrets store as > * G$BCKUPKEY_keyGuidString. > */ > >@@ -1360,22 +1334,7 @@ static WERROR bkrp_do_retrieve_server_wrap_key(TALLOC_CTX *mem_ctx, struct ldb_c > char *secret_name; > char *guid_string; > enum ndr_err_code ndr_err; >- >- status = get_lsa_secret(mem_ctx, ldb_ctx, "BCKUPKEY_P", &guid_binary); >- if (!NT_STATUS_IS_OK(status)) { >- DEBUG(10, ("Error while fetching secret BCKUPKEY_P to find current GUID\n")); >- return WERR_FILE_NOT_FOUND; >- } else if (guid_binary.length == 0) { >- /* RODC case, we do not have secrets locally */ >- DEBUG(1, ("Unable to fetch value for secret BCKUPKEY_P, are we an undetected RODC?\n")); >- return WERR_INTERNAL_ERROR; >- } > >- status = GUID_from_ndr_blob(&guid_binary, guid); >- if (!NT_STATUS_IS_OK(status)) { >- return WERR_FILE_NOT_FOUND; >- } >- > guid_string = GUID_string(mem_ctx, guid); > if (guid_string == NULL) { > /* We return file not found because the client >@@ -1392,7 +1351,7 @@ static WERROR bkrp_do_retrieve_server_wrap_key(TALLOC_CTX *mem_ctx, struct ldb_c > status = get_lsa_secret(mem_ctx, ldb_ctx, secret_name, &lsa_secret); > if (!NT_STATUS_IS_OK(status)) { > DEBUG(10, ("Error while fetching secret %s\n", secret_name)); >- return WERR_FILE_NOT_FOUND; >+ return WERR_INVALID_DATA; > } else if (guid_binary.length == 0) { > /* RODC case, we do not have secrets locally */ > DEBUG(1, ("Unable to fetch value for secret %s, are we an undetected RODC?\n", >@@ -1403,13 +1362,187 @@ static WERROR bkrp_do_retrieve_server_wrap_key(TALLOC_CTX *mem_ctx, struct ldb_c > (ndr_pull_flags_fn_t)ndr_pull_bkrp_dc_serverwrap_key); > if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { > DEBUG(2, ("Unable to parse the ndr encoded server wrap key %s\n", secret_name)); >+ return WERR_INVALID_DATA; >+ } >+ >+ return WERR_OK; >+} >+ >+/* >+ * Find the current, preferred ServerWrap Key by looking at >+ * G$BCKUPKEY_P in the LSA secrets store. >+ * >+ * Then find the current decryption keys from the LSA secrets store as >+ * G$BCKUPKEY_keyGuidString. >+ */ >+ >+static WERROR bkrp_do_retrieve_default_server_wrap_key(TALLOC_CTX *mem_ctx, >+ struct ldb_context *ldb_ctx, >+ struct bkrp_dc_serverwrap_key *server_key, >+ struct GUID *returned_guid) >+{ >+ NTSTATUS status; >+ DATA_BLOB guid_binary; >+ >+ status = get_lsa_secret(mem_ctx, ldb_ctx, "BCKUPKEY_P", &guid_binary); >+ if (!NT_STATUS_IS_OK(status)) { >+ DEBUG(10, ("Error while fetching secret BCKUPKEY_P to find current GUID\n")); >+ return WERR_FILE_NOT_FOUND; >+ } else if (guid_binary.length == 0) { >+ /* RODC case, we do not have secrets locally */ >+ DEBUG(1, ("Unable to fetch value for secret BCKUPKEY_P, are we an undetected RODC?\n")); >+ return WERR_INTERNAL_ERROR; >+ } >+ >+ status = GUID_from_ndr_blob(&guid_binary, returned_guid); >+ if (!NT_STATUS_IS_OK(status)) { > return WERR_FILE_NOT_FOUND; > } > >+ return bkrp_do_retrieve_server_wrap_key(mem_ctx, ldb_ctx, >+ server_key, returned_guid); >+} >+ >+static WERROR bkrp_server_wrap_decrypt_data(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, >+ struct bkrp_BackupKey *r ,struct ldb_context *ldb_ctx) >+{ >+ WERROR werr; >+ struct bkrp_server_side_wrapped decrypt_request; >+ DATA_BLOB sid_blob, encrypted_blob, symkey_blob; >+ DATA_BLOB blob; >+ enum ndr_err_code ndr_err; >+ struct bkrp_dc_serverwrap_key server_key; >+ struct bkrp_rc4encryptedpayload rc4payload; >+ struct dom_sid *caller_sid; >+ uint8_t symkey[20]; /* SHA-1 hash len */ >+ uint8_t mackey[20]; /* SHA-1 hash len */ >+ uint8_t mac[20]; /* SHA-1 hash len */ >+ unsigned int hash_len; >+ HMAC_CTX ctx; >+ >+ blob.data = r->in.data_in; >+ blob.length = r->in.data_in_len; >+ >+ if (r->in.data_in_len == 0 || r->in.data_in == NULL) { >+ return WERR_INVALID_PARAM; >+ } >+ >+ ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &decrypt_request, >+ (ndr_pull_flags_fn_t)ndr_pull_bkrp_server_side_wrapped); >+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { >+ return WERR_INVALID_PARAM; >+ } >+ >+ if (decrypt_request.magic != 1) { >+ return WERR_INVALID_PARAM; >+ } >+ >+ werr = bkrp_do_retrieve_server_wrap_key(mem_ctx, ldb_ctx, &server_key, >+ &decrypt_request.guid); >+ if (!W_ERROR_IS_OK(werr)) { >+ return werr; >+ } >+ >+ dump_data_pw("server_key: \n", server_key.key, sizeof(server_key.key)); >+ >+ dump_data_pw("r2: \n", decrypt_request.r2, sizeof(decrypt_request.r2)); >+ >+ /* >+ * This is *not* the leading 64 bytes, as indicated in MS-BKRP 3.1.4.1.1 >+ * BACKUPKEY_BACKUP_GUID, it really is the whole key >+ */ >+ HMAC(EVP_sha1(), server_key.key, sizeof(server_key.key), >+ decrypt_request.r2, sizeof(decrypt_request.r2), >+ symkey, &hash_len); >+ >+ dump_data_pw("symkey: \n", symkey, hash_len); >+ >+ /* rc4 decrypt sid and secret using sym key */ >+ symkey_blob = data_blob_const(symkey, sizeof(symkey)); >+ >+ encrypted_blob = data_blob_const(decrypt_request.rc4encryptedpayload, >+ decrypt_request.ciphertext_length); >+ >+ arcfour_crypt_blob(encrypted_blob.data, encrypted_blob.length, &symkey_blob); >+ >+ ndr_err = ndr_pull_struct_blob(&encrypted_blob, mem_ctx, &rc4payload, >+ (ndr_pull_flags_fn_t)ndr_pull_bkrp_rc4encryptedpayload); >+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { >+ return WERR_INVALID_PARAM; >+ } >+ >+ if (decrypt_request.payload_length != rc4payload.secret_data.length) { >+ return WERR_INVALID_PARAM; >+ } >+ >+ dump_data_pw("r3: \n", rc4payload.r3, sizeof(rc4payload.r3)); >+ >+ /* >+ * This is *not* the leading 64 bytes, as indicated in MS-BKRP 3.1.4.1.1 >+ * BACKUPKEY_BACKUP_GUID, it really is the whole key >+ */ >+ HMAC(EVP_sha1(), server_key.key, sizeof(server_key.key), >+ rc4payload.r3, sizeof(rc4payload.r3), >+ mackey, &hash_len); >+ >+ dump_data_pw("mackey: \n", mackey, sizeof(mackey)); >+ >+ ndr_err = ndr_push_struct_blob(&sid_blob, mem_ctx, &rc4payload.sid, >+ (ndr_push_flags_fn_t)ndr_push_dom_sid); >+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { >+ return WERR_INTERNAL_ERROR; >+ } >+ >+ HMAC_CTX_init(&ctx); >+ HMAC_Init_ex(&ctx, mackey, hash_len, EVP_sha1(), NULL); >+ /* SID field */ >+ HMAC_Update(&ctx, sid_blob.data, sid_blob.length); >+ /* Secret field */ >+ HMAC_Update(&ctx, rc4payload.secret_data.data, rc4payload.secret_data.length); >+ HMAC_Final(&ctx, mac, &hash_len); >+ HMAC_CTX_cleanup(&ctx); >+ >+ dump_data_pw("mac: \n", mac, sizeof(mac)); >+ dump_data_pw("rc4payload.mac: \n", rc4payload.mac, sizeof(rc4payload.mac)); >+ >+ if (memcmp(mac, rc4payload.mac, sizeof(mac)) != 0) { >+ return WERR_INVALID_ACCESS; >+ } >+ >+ caller_sid = &dce_call->conn->auth_state.session_info->security_token->sids[PRIMARY_USER_SID_INDEX]; >+ >+ if (!dom_sid_equal(&rc4payload.sid, caller_sid)) { >+ return WERR_INVALID_ACCESS; >+ } >+ >+ *(r->out.data_out) = rc4payload.secret_data.data; >+ *(r->out.data_out_len) = rc4payload.secret_data.length; >+ > return WERR_OK; > } > > /* >+ * For BACKUPKEY_RESTORE_GUID we need to check the first 4 bytes to >+ * determine what type of restore is wanted. >+ * >+ * See MS-BKRP 3.1.4.1.4 BACKUPKEY_RESTORE_GUID point 1. >+ */ >+ >+static WERROR bkrp_generic_decrypt_data(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, >+ struct bkrp_BackupKey *r, struct ldb_context *ldb_ctx) >+{ >+ if (r->in.data_in_len < 4 || r->in.data_in == NULL) { >+ return WERR_INVALID_PARAM; >+ } >+ >+ if (IVAL(r->in.data_in, 0) == 1) { >+ return bkrp_server_wrap_decrypt_data(dce_call, mem_ctx, r, ldb_ctx); >+ } >+ >+ return bkrp_client_wrap_decrypt_data(dce_call, mem_ctx, r, ldb_ctx); >+} >+ >+/* > * We have some data, such as saved website or IMAP passwords that the > * client would like to put into the profile on-disk. This needs to > * be encrypted. This version gives the server the data over the >@@ -1446,9 +1579,9 @@ static WERROR bkrp_server_wrap_encrypt_data(struct dcesrv_call_state *dce_call, > return WERR_INVALID_PARAM; > } > >- werr = bkrp_do_retrieve_server_wrap_key(mem_ctx, >- ldb_ctx, &server_key, >- &guid); >+ werr = bkrp_do_retrieve_default_server_wrap_key(mem_ctx, >+ ldb_ctx, &server_key, >+ &guid); > > if (!W_ERROR_IS_OK(werr)) { > if (W_ERROR_EQUAL(werr, WERR_FILE_NOT_FOUND)) { >@@ -1458,8 +1591,10 @@ static WERROR bkrp_server_wrap_encrypt_data(struct dcesrv_call_state *dce_call, > if (!W_ERROR_IS_OK(werr)) { > return WERR_INVALID_PARAMETER; > } >- werr = bkrp_do_retrieve_server_wrap_key(mem_ctx, >- ldb_ctx, &server_key, &guid); >+ werr = bkrp_do_retrieve_default_server_wrap_key(mem_ctx, >+ ldb_ctx, >+ &server_key, >+ &guid); > > if (W_ERROR_EQUAL(werr, WERR_FILE_NOT_FOUND)) { > /* Ok we really don't manage to get this secret ...*/ >@@ -1608,8 +1743,8 @@ static WERROR dcesrv_bkrp_BackupKey(struct dcesrv_call_state *dce_call, > if (!is_rodc) { > if(strncasecmp(GUID_string(mem_ctx, r->in.guidActionAgent), > BACKUPKEY_RESTORE_GUID, strlen(BACKUPKEY_RESTORE_GUID)) == 0) { >- DEBUG(debuglevel, ("Client %s requested to decrypt a client side wrapped secret\n", addr)); >- error = bkrp_client_wrap_decrypt_data(dce_call, mem_ctx, r, ldb_ctx); >+ DEBUG(debuglevel, ("Client %s requested to decrypt a wrapped secret\n", addr)); >+ error = bkrp_generic_decrypt_data(dce_call, mem_ctx, r, ldb_ctx); > } > > if (strncasecmp(GUID_string(mem_ctx, r->in.guidActionAgent), >@@ -1620,7 +1755,7 @@ static WERROR dcesrv_bkrp_BackupKey(struct dcesrv_call_state *dce_call, > > if (strncasecmp(GUID_string(mem_ctx, r->in.guidActionAgent), > BACKUPKEY_RESTORE_GUID_WIN2K, strlen(BACKUPKEY_RESTORE_GUID_WIN2K)) == 0) { >- DEBUG(debuglevel, ("Client %s requested to decrypt a server side wrapped secret, not implemented yet\n", addr)); >+ DEBUG(debuglevel, ("Client %s requested to decrypt a server side wrapped secret\n", addr)); > error = bkrp_server_wrap_decrypt_data(dce_call, mem_ctx, r, ldb_ctx); > } > >-- >1.9.1 > > >From 6ba863f6fde89c0f073e9aaa2aa46c044f781762 Mon Sep 17 00:00:00 2001 >From: Andrew Bartlett <abartlet@samba.org> >Date: Wed, 11 Feb 2015 13:37:16 +1300 >Subject: [PATCH 25/31] backupkey: Change expected error codes to match Windows > 2008R2 and Windows 2012R2 > >This is done in both smbtoture and in our server > >Signed-off-by: Andrew Bartlett <abartlet@samba.org> >--- > source4/rpc_server/backupkey/dcesrv_backupkey.c | 4 ++-- > source4/torture/rpc/backupkey.c | 11 +++++++++-- > 2 files changed, 11 insertions(+), 4 deletions(-) > >diff --git a/source4/rpc_server/backupkey/dcesrv_backupkey.c b/source4/rpc_server/backupkey/dcesrv_backupkey.c >index 4c9115c..22c86c7 100644 >--- a/source4/rpc_server/backupkey/dcesrv_backupkey.c >+++ b/source4/rpc_server/backupkey/dcesrv_backupkey.c >@@ -608,7 +608,7 @@ static WERROR bkrp_client_wrap_decrypt_data(struct dcesrv_call_state *dce_call, > &lsa_secret); > if (!NT_STATUS_IS_OK(status)) { > DEBUG(10, ("Error while fetching secret %s\n", cert_secret_name)); >- return WERR_FILE_NOT_FOUND; >+ return WERR_INVALID_DATA; > } else if (lsa_secret.length == 0) { > /* we do not have the real secret attribute, like if we are an RODC */ > return WERR_INVALID_PARAMETER; >@@ -661,7 +661,7 @@ static WERROR bkrp_client_wrap_decrypt_data(struct dcesrv_call_state *dce_call, > hx509_private_key_free(&pk); > if (res != 0) { > /* We are not able to decrypt the secret, looks like something is wrong */ >- return WERR_INVALID_DATA; >+ return WERR_INVALID_PARAMETER; > } > blob_us.data = uncrypted_secret.data; > blob_us.length = uncrypted_secret.length; >diff --git a/source4/torture/rpc/backupkey.c b/source4/torture/rpc/backupkey.c >index 8187643..967ea47 100644 >--- a/source4/torture/rpc/backupkey.c >+++ b/source4/torture/rpc/backupkey.c >@@ -775,7 +775,7 @@ static bool test_RestoreGUID_ko(struct torture_context *tctx, > out_blob.length = *r->out.data_out_len; > ndr_err = ndr_pull_struct_blob(&out_blob, tctx, &resp, (ndr_pull_flags_fn_t)ndr_pull_bkrp_client_side_unwrapped); > torture_assert_int_equal(tctx, NDR_ERR_CODE_IS_SUCCESS(ndr_err), 0, "Unable to unmarshall bkrp_client_side_unwrapped"); >- torture_assert_werr_equal(tctx, r->out.result, WERR_INVALID_DATA, "Wrong error code"); >+ torture_assert_werr_equal(tctx, r->out.result, WERR_INVALID_PARAM, "Wrong error code"); > } else { > struct bkrp_BackupKey *r = createRetreiveBackupKeyGUIDStruct(tctx, p, 2, &out_blob); > torture_assert_ntstatus_equal(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r), >@@ -980,7 +980,14 @@ static bool test_RestoreGUID_badcertguid(struct torture_context *tctx, > out_blob.length = *r->out.data_out_len; > ndr_err = ndr_pull_struct_blob(&out_blob, tctx, &resp, (ndr_pull_flags_fn_t)ndr_pull_bkrp_client_side_unwrapped); > torture_assert_int_equal(tctx, NDR_ERR_CODE_IS_SUCCESS(ndr_err), 0, "Unable to unmarshall bkrp_client_side_unwrapped"); >- torture_assert_werr_equal(tctx, r->out.result, WERR_FILE_NOT_FOUND, "Bad error code on wrong has in access check"); >+ >+ /* >+ * Windows 2012R2 has, presumably, a programming error >+ * returning an NTSTATUS code on this interface >+ */ >+ if (W_ERROR_V(r->out.result) != NT_STATUS_V(NT_STATUS_OBJECT_NAME_NOT_FOUND)) { >+ torture_assert_werr_equal(tctx, r->out.result, WERR_INVALID_DATA, "Bad error code on wrong has in access check"); >+ } > } else { > struct bkrp_BackupKey *r = createRetreiveBackupKeyGUIDStruct(tctx, p, 2, &out_blob); > torture_assert_ntstatus_equal(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r), >-- >1.9.1 > > >From 4fa5d3e6d02e9e6fda74e41813f2d41a1c7f85d9 Mon Sep 17 00:00:00 2001 >From: Andrew Bartlett <abartlet@samba.org> >Date: Wed, 11 Feb 2015 17:46:42 +1300 >Subject: [PATCH 26/31] backupkey: Add tests for ServerWrap protocol > >--- > source4/torture/rpc/backupkey.c | 647 +++++++++++++++++++++++++++++++++++++++- > 1 file changed, 645 insertions(+), 2 deletions(-) > >diff --git a/source4/torture/rpc/backupkey.c b/source4/torture/rpc/backupkey.c >index 967ea47..3abc2d7 100644 >--- a/source4/torture/rpc/backupkey.c >+++ b/source4/torture/rpc/backupkey.c >@@ -32,6 +32,16 @@ > #include <der.h> > #include <hcrypto/rsa.h> > >+enum test_wrong { >+ WRONG_MAGIC, >+ WRONG_R2, >+ WRONG_PAYLOAD_LENGTH, >+ WRONG_CIPHERTEXT_LENGTH, >+ SHORT_PAYLOAD_LENGTH, >+ SHORT_CIPHERTEXT_LENGTH, >+ ZERO_PAYLOAD_LENGTH, >+ ZERO_CIPHERTEXT_LENGTH >+}; > > /* Our very special and valued secret */ > /* No need to put const as we cast the array in uint8_t >@@ -1130,6 +1140,604 @@ static bool test_RetreiveBackupKeyGUID_2048bits(struct torture_context *tctx, > return true; > } > >+static bool test_ServerWrap_encrypt_decrypt(struct torture_context *tctx, >+ struct dcerpc_pipe *p) >+{ >+ struct bkrp_BackupKey r; >+ struct GUID guid; >+ DATA_BLOB plaintext = data_blob_const(secret, sizeof(secret)); >+ DATA_BLOB encrypted; >+ uint32_t enclen; >+ DATA_BLOB decrypted; >+ uint32_t declen; >+ struct dcerpc_binding_handle *b = p->binding_handle; >+ enum dcerpc_AuthType auth_type; >+ enum dcerpc_AuthLevel auth_level; >+ ZERO_STRUCT(r); >+ >+ dcerpc_binding_handle_auth_info(b, &auth_type, &auth_level); >+ >+ /* Encrypt */ >+ torture_assert_ntstatus_ok(tctx, >+ GUID_from_string(BACKUPKEY_BACKUP_GUID, &guid), >+ "obtain GUID"); >+ >+ r.in.guidActionAgent = &guid; >+ r.in.data_in = plaintext.data; >+ r.in.data_in_len = plaintext.length; >+ r.in.param = 0; >+ r.out.data_out = &encrypted.data; >+ r.out.data_out_len = &enclen; >+ if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) { >+ torture_assert_ntstatus_ok(tctx, >+ dcerpc_bkrp_BackupKey_r(b, tctx, &r), >+ "encrypt"); >+ } else { >+ torture_assert_ntstatus_equal(tctx, >+ dcerpc_bkrp_BackupKey_r(b, tctx, &r), >+ NT_STATUS_ACCESS_DENIED, >+ "encrypt"); >+ return true; >+ } >+ torture_assert_werr_ok(tctx, >+ r.out.result, >+ "encrypt"); >+ encrypted.length = *r.out.data_out_len; >+ >+ /* Decrypt */ >+ torture_assert_ntstatus_ok(tctx, >+ GUID_from_string(BACKUPKEY_RESTORE_GUID, &guid), >+ "obtain GUID"); >+ >+ r.in.guidActionAgent = &guid; >+ r.in.data_in = encrypted.data; >+ r.in.data_in_len = encrypted.length; >+ r.in.param = 0; >+ r.out.data_out = &(decrypted.data); >+ r.out.data_out_len = &declen; >+ torture_assert_ntstatus_ok(tctx, >+ dcerpc_bkrp_BackupKey_r(b, tctx, &r), >+ "decrypt"); >+ torture_assert_werr_ok(tctx, >+ r.out.result, >+ "decrypt"); >+ decrypted.length = *r.out.data_out_len; >+ >+ /* Compare */ >+ torture_assert_data_blob_equal(tctx, plaintext, decrypted, "Decrypt failed"); >+ >+ /* Decrypt */ >+ torture_assert_ntstatus_ok(tctx, >+ GUID_from_string(BACKUPKEY_RESTORE_GUID_WIN2K, &guid), >+ "obtain GUID"); >+ >+ r.in.guidActionAgent = &guid; >+ r.in.data_in = encrypted.data; >+ r.in.data_in_len = encrypted.length; >+ r.in.param = 0; >+ r.out.data_out = &(decrypted.data); >+ r.out.data_out_len = &declen; >+ torture_assert_ntstatus_ok(tctx, >+ dcerpc_bkrp_BackupKey_r(b, tctx, &r), >+ "decrypt"); >+ torture_assert_werr_ok(tctx, >+ r.out.result, >+ "decrypt"); >+ decrypted.length = *r.out.data_out_len; >+ >+ /* Compare */ >+ torture_assert_data_blob_equal(tctx, plaintext, decrypted, "Decrypt failed"); >+ return true; >+} >+ >+static bool test_ServerWrap_decrypt_wrong_keyGUID(struct torture_context *tctx, >+ struct dcerpc_pipe *p) >+{ >+ struct bkrp_BackupKey r; >+ struct GUID guid; >+ DATA_BLOB plaintext = data_blob_const(secret, sizeof(secret)); >+ DATA_BLOB encrypted; >+ uint32_t enclen; >+ DATA_BLOB decrypted; >+ uint32_t declen; >+ struct dcerpc_binding_handle *b = p->binding_handle; >+ enum ndr_err_code ndr_err; >+ struct bkrp_server_side_wrapped server_side_wrapped; >+ enum dcerpc_AuthType auth_type; >+ enum dcerpc_AuthLevel auth_level; >+ ZERO_STRUCT(r); >+ >+ dcerpc_binding_handle_auth_info(b, &auth_type, &auth_level); >+ >+ /* Encrypt */ >+ torture_assert_ntstatus_ok(tctx, >+ GUID_from_string(BACKUPKEY_BACKUP_GUID, &guid), >+ "obtain GUID"); >+ >+ r.in.guidActionAgent = &guid; >+ r.in.data_in = plaintext.data; >+ r.in.data_in_len = plaintext.length; >+ r.in.param = 0; >+ r.out.data_out = &encrypted.data; >+ r.out.data_out_len = &enclen; >+ if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) { >+ torture_assert_ntstatus_ok(tctx, >+ dcerpc_bkrp_BackupKey_r(b, tctx, &r), >+ "encrypt"); >+ } else { >+ torture_assert_ntstatus_equal(tctx, >+ dcerpc_bkrp_BackupKey_r(b, tctx, &r), >+ NT_STATUS_ACCESS_DENIED, >+ "encrypt"); >+ return true; >+ } >+ torture_assert_werr_ok(tctx, >+ r.out.result, >+ "encrypt"); >+ encrypted.length = *r.out.data_out_len; >+ >+ ndr_err = ndr_pull_struct_blob(&encrypted, tctx, &server_side_wrapped, >+ (ndr_pull_flags_fn_t)ndr_pull_bkrp_server_side_wrapped); >+ torture_assert_ndr_err_equal(tctx, ndr_err, NDR_ERR_SUCCESS, "pull of server_side_wrapped"); >+ >+ /* Change the GUID */ >+ server_side_wrapped.guid = GUID_random(); >+ >+ ndr_err = ndr_push_struct_blob(&encrypted, tctx, &server_side_wrapped, >+ (ndr_push_flags_fn_t)ndr_push_bkrp_server_side_wrapped); >+ torture_assert_ndr_err_equal(tctx, ndr_err, NDR_ERR_SUCCESS, "push of server_side_wrapped"); >+ >+ /* Decrypt */ >+ torture_assert_ntstatus_ok(tctx, >+ GUID_from_string(BACKUPKEY_RESTORE_GUID, &guid), >+ "obtain GUID"); >+ >+ r.in.guidActionAgent = &guid; >+ r.in.data_in = encrypted.data; >+ r.in.data_in_len = encrypted.length; >+ r.in.param = 0; >+ r.out.data_out = &(decrypted.data); >+ r.out.data_out_len = &declen; >+ torture_assert_ntstatus_ok(tctx, >+ dcerpc_bkrp_BackupKey_r(b, tctx, &r), >+ "decrypt"); >+ torture_assert_werr_equal(tctx, >+ r.out.result, >+ WERR_INVALID_DATA, >+ "decrypt should fail with WERR_INVALID_DATA"); >+ >+ /* Decrypt */ >+ torture_assert_ntstatus_ok(tctx, >+ GUID_from_string(BACKUPKEY_RESTORE_GUID_WIN2K, &guid), >+ "obtain GUID"); >+ >+ r.in.guidActionAgent = &guid; >+ r.in.data_in = encrypted.data; >+ r.in.data_in_len = encrypted.length; >+ r.in.param = 0; >+ r.out.data_out = &(decrypted.data); >+ r.out.data_out_len = &declen; >+ torture_assert_ntstatus_ok(tctx, >+ dcerpc_bkrp_BackupKey_r(b, tctx, &r), >+ "decrypt"); >+ torture_assert_werr_equal(tctx, >+ r.out.result, >+ WERR_INVALID_DATA, >+ "decrypt should fail with WERR_INVALID_DATA"); >+ >+ return true; >+} >+ >+static bool test_ServerWrap_decrypt_empty_request(struct torture_context *tctx, >+ struct dcerpc_pipe *p) >+{ >+ struct bkrp_BackupKey r; >+ struct GUID guid; >+ DATA_BLOB decrypted; >+ uint32_t declen; >+ struct dcerpc_binding_handle *b = p->binding_handle; >+ uint8_t short_request[4] = { 1, 0, 0, 0 }; >+ enum dcerpc_AuthType auth_type; >+ enum dcerpc_AuthLevel auth_level; >+ ZERO_STRUCT(r); >+ >+ dcerpc_binding_handle_auth_info(b, &auth_type, &auth_level); >+ >+ /* Decrypt */ >+ torture_assert_ntstatus_ok(tctx, >+ GUID_from_string(BACKUPKEY_RESTORE_GUID, &guid), >+ "obtain GUID"); >+ >+ r.in.guidActionAgent = &guid; >+ r.in.data_in = short_request; >+ r.in.data_in_len = 0; >+ r.in.param = 0; >+ r.out.data_out = &(decrypted.data); >+ r.out.data_out_len = &declen; >+ if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) { >+ torture_assert_ntstatus_ok(tctx, >+ dcerpc_bkrp_BackupKey_r(b, tctx, &r), >+ "encrypt"); >+ } else { >+ torture_assert_ntstatus_equal(tctx, >+ dcerpc_bkrp_BackupKey_r(b, tctx, &r), >+ NT_STATUS_ACCESS_DENIED, >+ "encrypt"); >+ return true; >+ } >+ torture_assert_werr_equal(tctx, >+ r.out.result, >+ WERR_INVALID_PARAM, >+ "decrypt should fail with WERR_INVALID_PARAM"); >+ >+ /* Decrypt */ >+ torture_assert_ntstatus_ok(tctx, >+ GUID_from_string(BACKUPKEY_RESTORE_GUID_WIN2K, &guid), >+ "obtain GUID"); >+ >+ r.in.guidActionAgent = &guid; >+ r.in.data_in = short_request; >+ r.in.data_in_len = 0; >+ r.in.param = 0; >+ r.out.data_out = &(decrypted.data); >+ r.out.data_out_len = &declen; >+ torture_assert_ntstatus_ok(tctx, >+ dcerpc_bkrp_BackupKey_r(b, tctx, &r), >+ "decrypt"); >+ torture_assert_werr_equal(tctx, >+ r.out.result, >+ WERR_INVALID_PARAM, >+ "decrypt should fail with WERR_INVALID_PARAM"); >+ >+ /* Decrypt */ >+ torture_assert_ntstatus_ok(tctx, >+ GUID_from_string(BACKUPKEY_RESTORE_GUID, &guid), >+ "obtain GUID"); >+ >+ r.in.guidActionAgent = &guid; >+ r.in.data_in = NULL; >+ r.in.data_in_len = 0; >+ r.in.param = 0; >+ r.out.data_out = &(decrypted.data); >+ r.out.data_out_len = &declen; >+ torture_assert_ntstatus_equal(tctx, >+ dcerpc_bkrp_BackupKey_r(b, tctx, &r), >+ NT_STATUS_INVALID_PARAMETER_MIX, >+ "decrypt"); >+ >+ /* Decrypt */ >+ torture_assert_ntstatus_ok(tctx, >+ GUID_from_string(BACKUPKEY_RESTORE_GUID_WIN2K, &guid), >+ "obtain GUID"); >+ >+ r.in.guidActionAgent = &guid; >+ r.in.data_in = NULL; >+ r.in.data_in_len = 0; >+ r.in.param = 0; >+ r.out.data_out = &(decrypted.data); >+ r.out.data_out_len = &declen; >+ torture_assert_ntstatus_equal(tctx, >+ dcerpc_bkrp_BackupKey_r(b, tctx, &r), >+ NT_STATUS_INVALID_PARAMETER_MIX, >+ "decrypt"); >+ >+ return true; >+} >+ >+ >+static bool test_ServerWrap_decrypt_short_request(struct torture_context *tctx, >+ struct dcerpc_pipe *p) >+{ >+ struct bkrp_BackupKey r; >+ struct GUID guid; >+ DATA_BLOB decrypted; >+ uint32_t declen; >+ struct dcerpc_binding_handle *b = p->binding_handle; >+ uint8_t short_request[4] = { 1, 0, 0, 0 }; >+ enum dcerpc_AuthType auth_type; >+ enum dcerpc_AuthLevel auth_level; >+ ZERO_STRUCT(r); >+ >+ dcerpc_binding_handle_auth_info(b, &auth_type, &auth_level); >+ >+ /* Decrypt */ >+ torture_assert_ntstatus_ok(tctx, >+ GUID_from_string(BACKUPKEY_RESTORE_GUID, &guid), >+ "obtain GUID"); >+ >+ r.in.guidActionAgent = &guid; >+ r.in.data_in = short_request; >+ r.in.data_in_len = 4; >+ r.in.param = 0; >+ r.out.data_out = &(decrypted.data); >+ r.out.data_out_len = &declen; >+ if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) { >+ torture_assert_ntstatus_ok(tctx, >+ dcerpc_bkrp_BackupKey_r(b, tctx, &r), >+ "encrypt"); >+ } else { >+ torture_assert_ntstatus_equal(tctx, >+ dcerpc_bkrp_BackupKey_r(b, tctx, &r), >+ NT_STATUS_ACCESS_DENIED, >+ "encrypt"); >+ return true; >+ } >+ torture_assert_werr_equal(tctx, >+ r.out.result, >+ WERR_INVALID_PARAM, >+ "decrypt should fail with WERR_INVALID_PARM"); >+ >+ /* Decrypt */ >+ torture_assert_ntstatus_ok(tctx, >+ GUID_from_string(BACKUPKEY_RESTORE_GUID_WIN2K, &guid), >+ "obtain GUID"); >+ >+ r.in.guidActionAgent = &guid; >+ r.in.data_in = short_request; >+ r.in.data_in_len = 4; >+ r.in.param = 0; >+ r.out.data_out = &(decrypted.data); >+ r.out.data_out_len = &declen; >+ torture_assert_ntstatus_ok(tctx, >+ dcerpc_bkrp_BackupKey_r(b, tctx, &r), >+ "decrypt"); >+ torture_assert_werr_equal(tctx, >+ r.out.result, >+ WERR_INVALID_PARAM, >+ "decrypt should fail with WERR_INVALID_PARAM"); >+ >+ /* Decrypt */ >+ torture_assert_ntstatus_ok(tctx, >+ GUID_from_string(BACKUPKEY_RESTORE_GUID, &guid), >+ "obtain GUID"); >+ >+ r.in.guidActionAgent = &guid; >+ r.in.data_in = short_request; >+ r.in.data_in_len = 1; >+ r.in.param = 0; >+ r.out.data_out = &(decrypted.data); >+ r.out.data_out_len = &declen; >+ torture_assert_ntstatus_ok(tctx, >+ dcerpc_bkrp_BackupKey_r(b, tctx, &r), >+ "decrypt"); >+ torture_assert_werr_equal(tctx, >+ r.out.result, >+ WERR_INVALID_PARAM, >+ "decrypt should fail with WERR_INVALID_PARAM"); >+ >+ /* Decrypt */ >+ torture_assert_ntstatus_ok(tctx, >+ GUID_from_string(BACKUPKEY_RESTORE_GUID_WIN2K, &guid), >+ "obtain GUID"); >+ >+ r.in.guidActionAgent = &guid; >+ r.in.data_in = short_request; >+ r.in.data_in_len = 1; >+ r.in.param = 0; >+ r.out.data_out = &(decrypted.data); >+ r.out.data_out_len = &declen; >+ torture_assert_ntstatus_ok(tctx, >+ dcerpc_bkrp_BackupKey_r(b, tctx, &r), >+ "decrypt"); >+ torture_assert_werr_equal(tctx, >+ r.out.result, >+ WERR_INVALID_PARAM, >+ "decrypt should fail with WERR_INVALID_PARAM"); >+ >+ return true; >+} >+ >+ >+static bool test_ServerWrap_decrypt_wrong_stuff(struct torture_context *tctx, >+ struct dcerpc_pipe *p, >+ enum test_wrong wrong) >+{ >+ struct bkrp_BackupKey r; >+ struct GUID guid; >+ DATA_BLOB plaintext = data_blob_const(secret, sizeof(secret)); >+ DATA_BLOB encrypted; >+ uint32_t enclen; >+ DATA_BLOB decrypted; >+ uint32_t declen; >+ struct dcerpc_binding_handle *b = p->binding_handle; >+ enum ndr_err_code ndr_err; >+ struct bkrp_server_side_wrapped server_side_wrapped; >+ bool repush = false; >+ enum dcerpc_AuthType auth_type; >+ enum dcerpc_AuthLevel auth_level; >+ ZERO_STRUCT(r); >+ >+ dcerpc_binding_handle_auth_info(b, &auth_type, &auth_level); >+ >+ /* Encrypt */ >+ torture_assert_ntstatus_ok(tctx, >+ GUID_from_string(BACKUPKEY_BACKUP_GUID, &guid), >+ "obtain GUID"); >+ >+ r.in.guidActionAgent = &guid; >+ r.in.data_in = plaintext.data; >+ r.in.data_in_len = plaintext.length; >+ r.in.param = 0; >+ r.out.data_out = &encrypted.data; >+ r.out.data_out_len = &enclen; >+ if (auth_level == DCERPC_AUTH_LEVEL_PRIVACY) { >+ torture_assert_ntstatus_ok(tctx, >+ dcerpc_bkrp_BackupKey_r(b, tctx, &r), >+ "encrypt"); >+ } else { >+ torture_assert_ntstatus_equal(tctx, >+ dcerpc_bkrp_BackupKey_r(b, tctx, &r), >+ NT_STATUS_ACCESS_DENIED, >+ "encrypt"); >+ return true; >+ } >+ torture_assert_werr_ok(tctx, >+ r.out.result, >+ "encrypt"); >+ encrypted.length = *r.out.data_out_len; >+ >+ ndr_err = ndr_pull_struct_blob(&encrypted, tctx, &server_side_wrapped, >+ (ndr_pull_flags_fn_t)ndr_pull_bkrp_server_side_wrapped); >+ torture_assert_ndr_err_equal(tctx, ndr_err, NDR_ERR_SUCCESS, "pull of server_side_wrapped"); >+ >+ torture_assert_int_equal(tctx, server_side_wrapped.payload_length, plaintext.length, >+ "wrong payload length"); >+ >+ switch (wrong) { >+ case WRONG_MAGIC: >+ /* Change the magic. Forced by our NDR layer, so do it raw */ >+ SIVAL(encrypted.data, 0, 78); /* valid values are 1-3 */ >+ break; >+ case WRONG_R2: >+ server_side_wrapped.r2[0] = 78; >+ server_side_wrapped.r2[1] = 78; >+ server_side_wrapped.r2[3] = 78; >+ repush = true; >+ break; >+ case WRONG_PAYLOAD_LENGTH: >+ server_side_wrapped.payload_length = UINT32_MAX - 8; >+ repush = true; >+ break; >+ case WRONG_CIPHERTEXT_LENGTH: >+ /* >+ * Change the ciphertext len. We can't push this if >+ * we have it wrong, so do it raw >+ */ >+ SIVAL(encrypted.data, 8, UINT32_MAX - 8); /* valid values are 1-3 */ >+ break; >+ case SHORT_PAYLOAD_LENGTH: >+ server_side_wrapped.payload_length = server_side_wrapped.payload_length - 8; >+ repush = true; >+ break; >+ case SHORT_CIPHERTEXT_LENGTH: >+ /* >+ * Change the ciphertext len. We can't push this if >+ * we have it wrong, so do it raw >+ */ >+ SIVAL(encrypted.data, 8, server_side_wrapped.ciphertext_length - 8); /* valid values are 1-3 */ >+ break; >+ case ZERO_PAYLOAD_LENGTH: >+ server_side_wrapped.payload_length = 0; >+ repush = true; >+ break; >+ case ZERO_CIPHERTEXT_LENGTH: >+ /* >+ * Change the ciphertext len. We can't push this if >+ * we have it wrong, so do it raw >+ */ >+ SIVAL(encrypted.data, 8, 0); /* valid values are 1-3 */ >+ break; >+ } >+ >+ if (repush) { >+ ndr_err = ndr_push_struct_blob(&encrypted, tctx, &server_side_wrapped, >+ (ndr_push_flags_fn_t)ndr_push_bkrp_server_side_wrapped); >+ torture_assert_ndr_err_equal(tctx, ndr_err, NDR_ERR_SUCCESS, "push of server_side_wrapped"); >+ } >+ >+ /* Decrypt */ >+ torture_assert_ntstatus_ok(tctx, >+ GUID_from_string(BACKUPKEY_RESTORE_GUID, &guid), >+ "obtain GUID"); >+ >+ r.in.guidActionAgent = &guid; >+ r.in.data_in = encrypted.data; >+ r.in.data_in_len = encrypted.length; >+ r.in.param = 0; >+ r.out.data_out = &(decrypted.data); >+ r.out.data_out_len = &declen; >+ torture_assert_ntstatus_ok(tctx, >+ dcerpc_bkrp_BackupKey_r(b, tctx, &r), >+ "decrypt"); >+ if (wrong == WRONG_R2 && W_ERROR_EQUAL(r.out.result, WERR_INVALID_SID)) { >+ torture_assert_werr_equal(tctx, >+ r.out.result, >+ WERR_INVALID_SID, >+ "decrypt should fail with WERR_INVALID_SID or WERR_INVALID_PARAM"); >+ } else { >+ torture_assert_werr_equal(tctx, >+ r.out.result, >+ WERR_INVALID_PARAM, >+ "decrypt should fail with WERR_INVALID_PARAM"); >+ } >+ >+ /* Decrypt */ >+ torture_assert_ntstatus_ok(tctx, >+ GUID_from_string(BACKUPKEY_RESTORE_GUID_WIN2K, &guid), >+ "obtain GUID"); >+ >+ r.in.guidActionAgent = &guid; >+ r.in.data_in = encrypted.data; >+ r.in.data_in_len = encrypted.length; >+ r.in.param = 0; >+ r.out.data_out = &(decrypted.data); >+ r.out.data_out_len = &declen; >+ torture_assert_ntstatus_ok(tctx, >+ dcerpc_bkrp_BackupKey_r(b, tctx, &r), >+ "decrypt"); >+ if (wrong == WRONG_R2 && W_ERROR_EQUAL(r.out.result, WERR_INVALID_SID)) { >+ torture_assert_werr_equal(tctx, >+ r.out.result, >+ WERR_INVALID_SID, >+ "decrypt should fail with WERR_INVALID_SID or WERR_INVALID_PARAM"); >+ } else { >+ torture_assert_werr_equal(tctx, >+ r.out.result, >+ WERR_INVALID_PARAM, >+ "decrypt should fail with WERR_INVALID_PARAM"); >+ } >+ >+ return true; >+} >+ >+static bool test_ServerWrap_decrypt_wrong_magic(struct torture_context *tctx, >+ struct dcerpc_pipe *p) >+{ >+ return test_ServerWrap_decrypt_wrong_stuff(tctx, p, WRONG_MAGIC); >+} >+ >+static bool test_ServerWrap_decrypt_wrong_r2(struct torture_context *tctx, >+ struct dcerpc_pipe *p) >+{ >+ return test_ServerWrap_decrypt_wrong_stuff(tctx, p, WRONG_R2); >+} >+ >+static bool test_ServerWrap_decrypt_wrong_payload_length(struct torture_context *tctx, >+ struct dcerpc_pipe *p) >+{ >+ return test_ServerWrap_decrypt_wrong_stuff(tctx, p, WRONG_PAYLOAD_LENGTH); >+} >+ >+static bool test_ServerWrap_decrypt_short_payload_length(struct torture_context *tctx, >+ struct dcerpc_pipe *p) >+{ >+ return test_ServerWrap_decrypt_wrong_stuff(tctx, p, SHORT_PAYLOAD_LENGTH); >+} >+ >+static bool test_ServerWrap_decrypt_zero_payload_length(struct torture_context *tctx, >+ struct dcerpc_pipe *p) >+{ >+ return test_ServerWrap_decrypt_wrong_stuff(tctx, p, ZERO_PAYLOAD_LENGTH); >+} >+ >+static bool test_ServerWrap_decrypt_wrong_ciphertext_length(struct torture_context *tctx, >+ struct dcerpc_pipe *p) >+{ >+ return test_ServerWrap_decrypt_wrong_stuff(tctx, p, WRONG_CIPHERTEXT_LENGTH); >+} >+ >+static bool test_ServerWrap_decrypt_short_ciphertext_length(struct torture_context *tctx, >+ struct dcerpc_pipe *p) >+{ >+ return test_ServerWrap_decrypt_wrong_stuff(tctx, p, SHORT_CIPHERTEXT_LENGTH); >+} >+ >+static bool test_ServerWrap_decrypt_zero_ciphertext_length(struct torture_context *tctx, >+ struct dcerpc_pipe *p) >+{ >+ return test_ServerWrap_decrypt_wrong_stuff(tctx, p, ZERO_CIPHERTEXT_LENGTH); >+} >+ > struct torture_suite *torture_rpc_backupkey(TALLOC_CTX *mem_ctx) > { > struct torture_rpc_tcase *tcase; >@@ -1147,7 +1755,7 @@ struct torture_suite *torture_rpc_backupkey(TALLOC_CTX *mem_ctx) > torture_rpc_tcase_add_test(tcase, "restore_guid version 3", > test_RestoreGUID_v3); > >-/* We double the test in order to be sure that we don't mess stuff (ie. freeing static stuff */ >+/* We double the test in order to be sure that we don't mess stuff (ie. freeing static stuff) */ > > torture_rpc_tcase_add_test(tcase, "restore_guid_2nd", > test_RestoreGUID); >@@ -1177,7 +1785,42 @@ struct torture_suite *torture_rpc_backupkey(TALLOC_CTX *mem_ctx) > test_RestoreGUID_emptyrequest); > > torture_rpc_tcase_add_test(tcase, "retreive_backup_key_guid_2048_bits", >- test_RetreiveBackupKeyGUID_2048bits); >+ test_RetreiveBackupKeyGUID_2048bits); >+ >+ torture_rpc_tcase_add_test(tcase, "server_wrap_encrypt_decrypt", >+ test_ServerWrap_encrypt_decrypt); >+ >+ torture_rpc_tcase_add_test(tcase, "server_wrap_decrypt_wrong_keyGUID", >+ test_ServerWrap_decrypt_wrong_keyGUID); >+ >+ torture_rpc_tcase_add_test(tcase, "server_wrap_empty_request", >+ test_ServerWrap_decrypt_empty_request); >+ >+ torture_rpc_tcase_add_test(tcase, "server_wrap_decrypt_short_request", >+ test_ServerWrap_decrypt_short_request); >+ >+ torture_rpc_tcase_add_test(tcase, "server_wrap_decrypt_wrong_magic", >+ test_ServerWrap_decrypt_wrong_magic); >+ >+ torture_rpc_tcase_add_test(tcase, "server_wrap_decrypt_wrong_r2", >+ test_ServerWrap_decrypt_wrong_r2); >+ >+ torture_rpc_tcase_add_test(tcase, "server_wrap_decrypt_wrong_payload_length", >+ test_ServerWrap_decrypt_wrong_payload_length); >+ >+ torture_rpc_tcase_add_test(tcase, "server_wrap_decrypt_short_payload_length", >+ test_ServerWrap_decrypt_short_payload_length); >+ >+ torture_rpc_tcase_add_test(tcase, "server_wrap_decrypt_zero_payload_length", >+ test_ServerWrap_decrypt_zero_payload_length); >+ >+ torture_rpc_tcase_add_test(tcase, "server_wrap_decrypt_wrong_ciphertext_length", >+ test_ServerWrap_decrypt_wrong_ciphertext_length); >+ >+ torture_rpc_tcase_add_test(tcase, "server_wrap_decrypt_short_ciphertext_length", >+ test_ServerWrap_decrypt_short_ciphertext_length); > >+ torture_rpc_tcase_add_test(tcase, "server_wrap_decrypt_zero_ciphertext_length", >+ test_ServerWrap_decrypt_zero_ciphertext_length); > return suite; > } >-- >1.9.1 > > >From b5905f3be4bbcb67a472c877da5cd712314e25a7 Mon Sep 17 00:00:00 2001 >From: Andrew Bartlett <abartlet@samba.org> >Date: Thu, 12 Feb 2015 16:15:41 +1300 >Subject: [PATCH 27/31] backupkey: Better handling for different wrap version > headers > >--- > librpc/idl/backupkey.idl | 6 +++++ > source4/rpc_server/backupkey/dcesrv_backupkey.c | 31 +++++++++++++++---------- > 2 files changed, 25 insertions(+), 12 deletions(-) > >diff --git a/librpc/idl/backupkey.idl b/librpc/idl/backupkey.idl >index 76c0eb7..81e0db6 100644 >--- a/librpc/idl/backupkey.idl >+++ b/librpc/idl/backupkey.idl >@@ -119,6 +119,12 @@ interface backupkey > } bkrp_opaque_blob; > > typedef enum { >+ BACKUPKEY_SERVER_WRAP_VERSION = 1, >+ BACKUPKEY_CLIENT_WRAP_VERSION2 = 2, >+ BACKUPKEY_CLIENT_WRAP_VERSION3 = 3 >+ } bkrp_versions; >+ >+ typedef enum { > BACKUPKEY_INVALID_GUID_INTEGER = 0xFFFF, > BACKUPKEY_RESTORE_GUID_INTEGER = 0x0000, > BACKUPKEY_RETRIEVE_BACKUP_KEY_GUID_INTEGER = 0x0001, >diff --git a/source4/rpc_server/backupkey/dcesrv_backupkey.c b/source4/rpc_server/backupkey/dcesrv_backupkey.c >index 22c86c7..5a2e8a4 100644 >--- a/source4/rpc_server/backupkey/dcesrv_backupkey.c >+++ b/source4/rpc_server/backupkey/dcesrv_backupkey.c >@@ -42,9 +42,6 @@ > #include "librpc/gen_ndr/ndr_security.h" > #include "lib/crypto/arcfour.h" > >-#define BACKUPKEY_MIN_VERSION 2 >-#define BACKUPKEY_MAX_VERSION 3 >- > static const unsigned rsa_with_var_num[] = { 1, 2, 840, 113549, 1, 1, 1 }; > /* Equivalent to asn1_oid_id_pkcs1_rsaEncryption*/ > static const AlgorithmIdentifier _hx509_signature_rsa_with_var_num = { >@@ -568,25 +565,35 @@ static WERROR bkrp_client_wrap_decrypt_data(struct dcesrv_call_state *dce_call, > DATA_BLOB lsa_secret; > DATA_BLOB *uncrypted_data; > NTSTATUS status; >- >+ uint32_t requested_version; >+ > blob.data = r->in.data_in; > blob.length = r->in.data_in_len; > >- if (r->in.data_in_len == 0 || r->in.data_in == NULL) { >+ if (r->in.data_in_len < 4 || r->in.data_in == NULL) { > return WERR_INVALID_PARAM; > } > >+ /* >+ * We check for the version here, so we can actually print the >+ * message as we are unlikely to parse it with NDR. >+ */ >+ requested_version = IVAL(r->in.data_in, 0); >+ if ((requested_version != BACKUPKEY_CLIENT_WRAP_VERSION2) >+ && (requested_version != BACKUPKEY_CLIENT_WRAP_VERSION3)) { >+ DEBUG(1, ("Request for unknown BackupKey sub-protocol %d\n", requested_version)); >+ return WERR_INVALID_PARAMETER; >+ } >+ > ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &uncrypt_request, > (ndr_pull_flags_fn_t)ndr_pull_bkrp_client_side_wrapped); > if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { > return WERR_INVALID_PARAM; > } > >- if (uncrypt_request.version < BACKUPKEY_MIN_VERSION) { >- return WERR_INVALID_PARAMETER; >- } >- >- if (uncrypt_request.version > BACKUPKEY_MAX_VERSION) { >+ if ((uncrypt_request.version != BACKUPKEY_CLIENT_WRAP_VERSION2) >+ && (uncrypt_request.version != BACKUPKEY_CLIENT_WRAP_VERSION3)) { >+ DEBUG(1, ("Request for unknown BackupKey sub-protocol %d\n", uncrypt_request.version)); > return WERR_INVALID_PARAMETER; > } > >@@ -1433,7 +1440,7 @@ static WERROR bkrp_server_wrap_decrypt_data(struct dcesrv_call_state *dce_call, > return WERR_INVALID_PARAM; > } > >- if (decrypt_request.magic != 1) { >+ if (decrypt_request.magic != BACKUPKEY_SERVER_WRAP_VERSION) { > return WERR_INVALID_PARAM; > } > >@@ -1535,7 +1542,7 @@ static WERROR bkrp_generic_decrypt_data(struct dcesrv_call_state *dce_call, TALL > return WERR_INVALID_PARAM; > } > >- if (IVAL(r->in.data_in, 0) == 1) { >+ if (IVAL(r->in.data_in, 0) == BACKUPKEY_SERVER_WRAP_VERSION) { > return bkrp_server_wrap_decrypt_data(dce_call, mem_ctx, r, ldb_ctx); > } > >-- >1.9.1 > > >From d24b833d277f6cd6889deb8eea1aeff9ffd3ec0d Mon Sep 17 00:00:00 2001 >From: Andrew Bartlett <abartlet@samba.org> >Date: Fri, 13 Feb 2015 12:59:45 +1300 >Subject: [PATCH 28/31] torture-backupkey: Add tests that read the secret from > the server, and validate > >These show that MS-BKRP 3.1.4.1.1 BACKUPKEY_BACKUP_GUID is incorrect when it >states that the key must be the leading 64 bytes, it must be the whole 256 byte >buffer. > >Signed-off-by: Andrew Bartlett <abartlet@samba.org> >--- > source4/torture/rpc/backupkey.c | 321 ++++++++++++++++++++++++++++++++++++++-- > 1 file changed, 312 insertions(+), 9 deletions(-) > >diff --git a/source4/torture/rpc/backupkey.c b/source4/torture/rpc/backupkey.c >index 3abc2d7..53caf74 100644 >--- a/source4/torture/rpc/backupkey.c >+++ b/source4/torture/rpc/backupkey.c >@@ -23,14 +23,21 @@ > #include "librpc/gen_ndr/ndr_backupkey_c.h" > #include "librpc/gen_ndr/ndr_backupkey.h" > #include "librpc/gen_ndr/ndr_lsa_c.h" >+#include "librpc/gen_ndr/ndr_security.h" > #include "torture/rpc/torture_rpc.h" >+#include "torture/ndr/ndr.h" > #include "lib/cmdline/popt_common.h" >+#include "libcli/auth/proto.h" >+#include "lib/crypto/arcfour.h" > #include <com_err.h> > #include <hcrypto/sha.h> > #include <system/network.h> > #include <hx509.h> > #include <der.h> > #include <hcrypto/rsa.h> >+#include <hcrypto/hmac.h> >+#include <hcrypto/sha.h> >+#include <hcrypto/evp.h> > > enum test_wrong { > WRONG_MAGIC, >@@ -40,7 +47,10 @@ enum test_wrong { > SHORT_PAYLOAD_LENGTH, > SHORT_CIPHERTEXT_LENGTH, > ZERO_PAYLOAD_LENGTH, >- ZERO_CIPHERTEXT_LENGTH >+ ZERO_CIPHERTEXT_LENGTH, >+ RIGHT_KEY, >+ WRONG_KEY, >+ WRONG_SID, > }; > > /* Our very special and valued secret */ >@@ -50,10 +60,9 @@ enum test_wrong { > static const char secret[] = "tata yoyo mais qu'est ce qu'il y a sous ton grand chapeau ?"; > > /* Get the SID from a user */ >-static const struct dom_sid *get_user_sid(struct torture_context *tctx, >- struct dcerpc_pipe *p, >- TALLOC_CTX *mem_ctx, >- const char *user) >+static struct dom_sid *get_user_sid(struct torture_context *tctx, >+ TALLOC_CTX *mem_ctx, >+ const char *user) > { > struct lsa_ObjectAttribute attr; > struct lsa_QosInfo qos; >@@ -258,7 +267,7 @@ static DATA_BLOB *create_access_check(struct torture_context *tctx, > TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); > DATA_BLOB *blob = talloc_zero(mem_ctx, DATA_BLOB); > enum ndr_err_code ndr_err; >- const struct dom_sid *sid = get_user_sid(tctx, p, tmp_ctx, user); >+ const struct dom_sid *sid = get_user_sid(tctx, tmp_ctx, user); > > if (sid == NULL) { > return NULL; >@@ -1527,6 +1536,239 @@ static bool test_ServerWrap_decrypt_short_request(struct torture_context *tctx, > return true; > } > >+static bool test_ServerWrap_encrypt_decrypt_manual(struct torture_context *tctx, >+ struct bkrp_server_side_wrapped *server_side_wrapped, >+ enum test_wrong wrong) >+{ >+ struct dcerpc_pipe *lsa_p; >+ struct dcerpc_binding_handle *lsa_b; >+ struct lsa_OpenSecret r_secret; >+ struct lsa_QuerySecret r_query_secret; >+ struct policy_handle *handle, sec_handle; >+ struct bkrp_BackupKey r; >+ struct GUID preferred_key_guid; >+ DATA_BLOB plaintext = data_blob_const(secret, sizeof(secret)); >+ DATA_BLOB preferred_key, preferred_key_clear, session_key, >+ decrypt_key, decrypt_key_clear, encrypted_blob, symkey_blob, >+ sid_blob; >+ struct bkrp_dc_serverwrap_key server_key; >+ struct lsa_DATA_BUF_PTR bufp1; >+ char *key_guid_string; >+ struct bkrp_rc4encryptedpayload rc4payload; >+ struct dom_sid *caller_sid; >+ uint8_t symkey[20]; /* SHA-1 hash len */ >+ uint8_t mackey[20]; /* SHA-1 hash len */ >+ uint8_t mac[20]; /* SHA-1 hash len */ >+ unsigned int hash_len; >+ HMAC_CTX ctx; >+ ZERO_STRUCT(r); >+ ZERO_STRUCT(r_secret); >+ ZERO_STRUCT(r_query_secret); >+ >+ /* Now read BCKUPKEY_P and prove we can do a matching decrypt and encrypt */ >+ >+ torture_assert_ntstatus_ok(tctx, >+ torture_rpc_connection(tctx, &lsa_p, &ndr_table_lsarpc), >+ "Opening LSA pipe"); >+ lsa_b = lsa_p->binding_handle; >+ >+ torture_assert(tctx, test_lsa_OpenPolicy2(lsa_b, tctx, &handle), "OpenPolicy failed"); >+ r_secret.in.name.string = "G$BCKUPKEY_P"; >+ >+ r_secret.in.handle = handle; >+ r_secret.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; >+ r_secret.out.sec_handle = &sec_handle; >+ >+ torture_comment(tctx, "Testing OpenSecret\n"); >+ >+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_OpenSecret_r(lsa_b, tctx, &r_secret), >+ "OpenSecret failed"); >+ torture_assert_ntstatus_ok(tctx, r_secret.out.result, >+ "OpenSecret failed"); >+ >+ r_query_secret.in.sec_handle = &sec_handle; >+ r_query_secret.in.new_val = &bufp1; >+ bufp1.buf = NULL; >+ >+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_QuerySecret_r(lsa_b, tctx, &r_query_secret), >+ "QuerySecret failed"); >+ torture_assert_ntstatus_ok(tctx, r_query_secret.out.result, >+ "QuerySecret failed"); >+ >+ >+ preferred_key.data = r_query_secret.out.new_val->buf->data; >+ preferred_key.length = r_query_secret.out.new_val->buf->size; >+ torture_assert_ntstatus_ok(tctx, dcerpc_fetch_session_key(lsa_p, &session_key), >+ "dcerpc_fetch_session_key failed"); >+ >+ torture_assert_ntstatus_ok(tctx, >+ sess_decrypt_blob(tctx, >+ &preferred_key, &session_key, &preferred_key_clear), >+ "sess_decrypt_blob failed"); >+ >+ torture_assert_ntstatus_ok(tctx, GUID_from_ndr_blob(&preferred_key_clear, &preferred_key_guid), >+ "GUID parse failed"); >+ >+ torture_assert_guid_equal(tctx, server_side_wrapped->guid, >+ preferred_key_guid, >+ "GUID didn't match value pointed at by G$BCKUPKEY_P"); >+ >+ /* And read BCKUPKEY_<guid> and get the actual key */ >+ >+ key_guid_string = GUID_string(tctx, &server_side_wrapped->guid); >+ r_secret.in.name.string = talloc_asprintf(tctx, "G$BCKUPKEY_%s", key_guid_string); >+ >+ r_secret.in.handle = handle; >+ r_secret.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED; >+ r_secret.out.sec_handle = &sec_handle; >+ >+ torture_comment(tctx, "Testing OpenSecret\n"); >+ >+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_OpenSecret_r(lsa_b, tctx, &r_secret), >+ "OpenSecret failed"); >+ torture_assert_ntstatus_ok(tctx, r_secret.out.result, >+ "OpenSecret failed"); >+ >+ r_query_secret.in.sec_handle = &sec_handle; >+ r_query_secret.in.new_val = &bufp1; >+ >+ torture_assert_ntstatus_ok(tctx, dcerpc_lsa_QuerySecret_r(lsa_b, tctx, &r_query_secret), >+ "QuerySecret failed"); >+ torture_assert_ntstatus_ok(tctx, r_query_secret.out.result, >+ "QuerySecret failed"); >+ >+ >+ decrypt_key.data = r_query_secret.out.new_val->buf->data; >+ decrypt_key.length = r_query_secret.out.new_val->buf->size; >+ >+ torture_assert_ntstatus_ok(tctx, >+ sess_decrypt_blob(tctx, >+ &decrypt_key, &session_key, &decrypt_key_clear), >+ "sess_decrypt_blob failed"); >+ >+ torture_assert_ndr_err_equal(tctx, ndr_pull_struct_blob(&decrypt_key_clear, tctx, &server_key, >+ (ndr_pull_flags_fn_t)ndr_pull_bkrp_dc_serverwrap_key), >+ NDR_ERR_SUCCESS, "Failed to parse server_key"); >+ >+ torture_assert_int_equal(tctx, server_key.magic, 1, "Failed to correctly decrypt server key"); >+ >+ /* >+ * This is *not* the leading 64 bytes, as indicated in MS-BKRP 3.1.4.1.1 >+ * BACKUPKEY_BACKUP_GUID, it really is the whole key >+ */ >+ HMAC(EVP_sha1(), server_key.key, sizeof(server_key.key), >+ server_side_wrapped->r2, sizeof(server_side_wrapped->r2), >+ symkey, &hash_len); >+ >+ /* rc4 decrypt sid and secret using sym key */ >+ symkey_blob = data_blob_const(symkey, sizeof(symkey)); >+ >+ encrypted_blob = data_blob_talloc(tctx, server_side_wrapped->rc4encryptedpayload, >+ server_side_wrapped->ciphertext_length); >+ >+ arcfour_crypt_blob(encrypted_blob.data, encrypted_blob.length, &symkey_blob); >+ >+ torture_assert_ndr_err_equal(tctx, ndr_pull_struct_blob(&encrypted_blob, tctx, &rc4payload, >+ (ndr_pull_flags_fn_t)ndr_pull_bkrp_rc4encryptedpayload), >+ NDR_ERR_SUCCESS, "Failed to parse rc4encryptedpayload"); >+ >+ torture_assert_int_equal(tctx, rc4payload.secret_data.length, >+ server_side_wrapped->payload_length, >+ "length of decrypted payload not the length declared in surrounding structure"); >+ >+ /* >+ * This is *not* the leading 64 bytes, as indicated in MS-BKRP 3.1.4.1.1 >+ * BACKUPKEY_BACKUP_GUID, it really is the whole key >+ */ >+ HMAC(EVP_sha1(), server_key.key, sizeof(server_key.key), >+ rc4payload.r3, sizeof(rc4payload.r3), >+ mackey, &hash_len); >+ >+ torture_assert_ndr_err_equal(tctx, ndr_push_struct_blob(&sid_blob, tctx, &rc4payload.sid, >+ (ndr_push_flags_fn_t)ndr_push_dom_sid), >+ NDR_ERR_SUCCESS, "unable to push SID"); >+ >+ HMAC_CTX_init(&ctx); >+ HMAC_Init_ex(&ctx, mackey, hash_len, EVP_sha1(), NULL); >+ /* SID field */ >+ HMAC_Update(&ctx, sid_blob.data, sid_blob.length); >+ /* Secret field */ >+ HMAC_Update(&ctx, rc4payload.secret_data.data, rc4payload.secret_data.length); >+ HMAC_Final(&ctx, mac, &hash_len); >+ HMAC_CTX_cleanup(&ctx); >+ >+ torture_assert_mem_equal(tctx, mac, rc4payload.mac, sizeof(mac), "mac not correct"); >+ torture_assert_int_equal(tctx, rc4payload.secret_data.length, >+ plaintext.length, "decrypted data is not correct length"); >+ torture_assert_mem_equal(tctx, rc4payload.secret_data.data, >+ plaintext.data, plaintext.length, >+ "decrypted data is not correct"); >+ >+ /* Not strictly correct all the time, but good enough for this test */ >+ caller_sid = get_user_sid(tctx, tctx, cli_credentials_get_username(cmdline_credentials)); >+ >+ torture_assert_sid_equal(tctx, &rc4payload.sid, caller_sid, "Secret saved with wrong SID"); >+ >+ >+ /* RE-encrypt */ >+ >+ if (wrong == WRONG_SID) { >+ rc4payload.sid.sub_auths[rc4payload.sid.num_auths - 1] = DOMAIN_RID_KRBTGT; >+ } >+ >+ dump_data_pw("mackey: \n", mackey, sizeof(mackey)); >+ >+ torture_assert_ndr_err_equal(tctx, >+ ndr_push_struct_blob(&sid_blob, tctx, &rc4payload.sid, >+ (ndr_push_flags_fn_t)ndr_push_dom_sid), >+ NDR_ERR_SUCCESS, >+ "push of sid failed"); >+ >+ HMAC_CTX_init(&ctx); >+ HMAC_Init_ex(&ctx, mackey, 20, EVP_sha1(), NULL); >+ /* SID field */ >+ HMAC_Update(&ctx, sid_blob.data, sid_blob.length); >+ /* Secret field */ >+ HMAC_Update(&ctx, rc4payload.secret_data.data, rc4payload.secret_data.length); >+ HMAC_Final(&ctx, rc4payload.mac, &hash_len); >+ HMAC_CTX_cleanup(&ctx); >+ >+ dump_data_pw("rc4payload.mac: \n", rc4payload.mac, sizeof(rc4payload.mac)); >+ >+ torture_assert_ndr_err_equal(tctx, >+ ndr_push_struct_blob(&encrypted_blob, tctx, &rc4payload, >+ (ndr_push_flags_fn_t)ndr_push_bkrp_rc4encryptedpayload), >+ NDR_ERR_SUCCESS, >+ "push of rc4payload failed"); >+ >+ if (wrong == WRONG_KEY) { >+ symkey_blob.data[0] = 78; >+ symkey_blob.data[1] = 78; >+ symkey_blob.data[2] = 78; >+ } >+ >+ /* rc4 encrypt sid and secret using sym key */ >+ arcfour_crypt_blob(encrypted_blob.data, encrypted_blob.length, &symkey_blob); >+ >+ /* re-create server wrap structure */ >+ >+ torture_assert_int_equal(tctx, encrypted_blob.length, >+ server_side_wrapped->ciphertext_length, >+ "expected encrypted length not to change"); >+ if (wrong == RIGHT_KEY) { >+ torture_assert_mem_equal(tctx, server_side_wrapped->rc4encryptedpayload, >+ encrypted_blob.data, >+ encrypted_blob.length, >+ "expected encrypted data not to change"); >+ } >+ >+ server_side_wrapped->payload_length = rc4payload.secret_data.length; >+ server_side_wrapped->ciphertext_length = encrypted_blob.length; >+ server_side_wrapped->rc4encryptedpayload = encrypted_blob.data; >+ >+ return true; >+} >+ > > static bool test_ServerWrap_decrypt_wrong_stuff(struct torture_context *tctx, > struct dcerpc_pipe *p, >@@ -1627,6 +1869,15 @@ static bool test_ServerWrap_decrypt_wrong_stuff(struct torture_context *tctx, > */ > SIVAL(encrypted.data, 8, 0); /* valid values are 1-3 */ > break; >+ >+ case RIGHT_KEY: >+ case WRONG_KEY: >+ case WRONG_SID: >+ torture_assert(tctx, >+ test_ServerWrap_encrypt_decrypt_manual(tctx, &server_side_wrapped, wrong), >+ "test_ServerWrap_encrypt_decrypt_manual failed"); >+ repush = true; >+ break; > } > > if (repush) { >@@ -1649,11 +1900,23 @@ static bool test_ServerWrap_decrypt_wrong_stuff(struct torture_context *tctx, > torture_assert_ntstatus_ok(tctx, > dcerpc_bkrp_BackupKey_r(b, tctx, &r), > "decrypt"); >- if (wrong == WRONG_R2 && W_ERROR_EQUAL(r.out.result, WERR_INVALID_SID)) { >+ >+ if ((wrong == WRONG_R2 || wrong == WRONG_KEY) >+ && W_ERROR_EQUAL(r.out.result, WERR_INVALID_SID)) { > torture_assert_werr_equal(tctx, > r.out.result, > WERR_INVALID_SID, > "decrypt should fail with WERR_INVALID_SID or WERR_INVALID_PARAM"); >+ } else if (wrong == RIGHT_KEY) { >+ torture_assert_werr_equal(tctx, >+ r.out.result, >+ WERR_OK, >+ "decrypt should succeed!"); >+ } else if (wrong == WRONG_SID) { >+ torture_assert_werr_equal(tctx, >+ r.out.result, >+ WERR_INVALID_ACCESS, >+ "decrypt should fail with WERR_INVALID_ACCESS"); > } else { > torture_assert_werr_equal(tctx, > r.out.result, >@@ -1675,11 +1938,23 @@ static bool test_ServerWrap_decrypt_wrong_stuff(struct torture_context *tctx, > torture_assert_ntstatus_ok(tctx, > dcerpc_bkrp_BackupKey_r(b, tctx, &r), > "decrypt"); >- if (wrong == WRONG_R2 && W_ERROR_EQUAL(r.out.result, WERR_INVALID_SID)) { >+ >+ if ((wrong == WRONG_R2 || wrong == WRONG_KEY) >+ && W_ERROR_EQUAL(r.out.result, WERR_INVALID_SID)) { > torture_assert_werr_equal(tctx, > r.out.result, > WERR_INVALID_SID, > "decrypt should fail with WERR_INVALID_SID or WERR_INVALID_PARAM"); >+ } else if (wrong == RIGHT_KEY) { >+ torture_assert_werr_equal(tctx, >+ r.out.result, >+ WERR_OK, >+ "decrypt should succeed!"); >+ } else if (wrong == WRONG_SID) { >+ torture_assert_werr_equal(tctx, >+ r.out.result, >+ WERR_INVALID_ACCESS, >+ "decrypt should fail with WERR_INVALID_ACCESS"); > } else { > torture_assert_werr_equal(tctx, > r.out.result, >@@ -1733,11 +2008,29 @@ static bool test_ServerWrap_decrypt_short_ciphertext_length(struct torture_conte > } > > static bool test_ServerWrap_decrypt_zero_ciphertext_length(struct torture_context *tctx, >- struct dcerpc_pipe *p) >+ struct dcerpc_pipe *p) > { > return test_ServerWrap_decrypt_wrong_stuff(tctx, p, ZERO_CIPHERTEXT_LENGTH); > } > >+static bool test_ServerWrap_encrypt_decrypt_remote_key(struct torture_context *tctx, >+ struct dcerpc_pipe *p) >+{ >+ return test_ServerWrap_decrypt_wrong_stuff(tctx, p, RIGHT_KEY); >+} >+ >+static bool test_ServerWrap_encrypt_decrypt_wrong_key(struct torture_context *tctx, >+ struct dcerpc_pipe *p) >+{ >+ return test_ServerWrap_decrypt_wrong_stuff(tctx, p, WRONG_KEY); >+} >+ >+static bool test_ServerWrap_encrypt_decrypt_wrong_sid(struct torture_context *tctx, >+ struct dcerpc_pipe *p) >+{ >+ return test_ServerWrap_decrypt_wrong_stuff(tctx, p, WRONG_SID); >+} >+ > struct torture_suite *torture_rpc_backupkey(TALLOC_CTX *mem_ctx) > { > struct torture_rpc_tcase *tcase; >@@ -1822,5 +2115,15 @@ struct torture_suite *torture_rpc_backupkey(TALLOC_CTX *mem_ctx) > > torture_rpc_tcase_add_test(tcase, "server_wrap_decrypt_zero_ciphertext_length", > test_ServerWrap_decrypt_zero_ciphertext_length); >+ >+ torture_rpc_tcase_add_test(tcase, "server_wrap_encrypt_decrypt_remote_key", >+ test_ServerWrap_encrypt_decrypt_remote_key); >+ >+ torture_rpc_tcase_add_test(tcase, "server_wrap_encrypt_decrypt_wrong_key", >+ test_ServerWrap_encrypt_decrypt_wrong_key); >+ >+ torture_rpc_tcase_add_test(tcase, "server_wrap_encrypt_decrypt_wrong_sid", >+ test_ServerWrap_encrypt_decrypt_wrong_sid); >+ > return suite; > } >-- >1.9.1 > > >From 6a8ee822a2d7e78822813a1876c23f14b8124ba9 Mon Sep 17 00:00:00 2001 >From: Garming Sam <garming@catalyst.net.nz> >Date: Fri, 13 Feb 2015 16:49:58 +1300 >Subject: [PATCH 29/31] build: Require GnuTLS if building with Active Directory > >Without GnuTLS, we don't have ldaps:// support and we are unable to >readily create RSA keys of the correct length for the BackupKey >protocol. > >Signed-off-by: Garming Sam <garming@catalyst.net.nz> >--- > source4/lib/tls/wscript | 3 +++ > 1 file changed, 3 insertions(+) > >diff --git a/source4/lib/tls/wscript b/source4/lib/tls/wscript >index 57cd894..ae96395 100644 >--- a/source4/lib/tls/wscript >+++ b/source4/lib/tls/wscript >@@ -25,6 +25,9 @@ def configure(conf): > > if 'HAVE_GNUTLS' in conf.env: > conf.DEFINE('ENABLE_GNUTLS', 1) >+ else: >+ if 'AD_DC_BUILD_IS_ENABLED' in conf.env: >+ conf.fatal("Building the AD DC requires GnuTLS (eg libgnutls-dev, gnutls-devel) for ldaps:// support and for the BackupKey protocol") > > conf.CHECK_FUNCS_IN('gnutls_global_init', 'gnutls', > headers='gnutls/gnutls.h') >-- >1.9.1 > > >From 428d8fe2161decc04c0ae37d0372c50450fe9312 Mon Sep 17 00:00:00 2001 >From: Garming Sam <garming@catalyst.net.nz> >Date: Fri, 13 Feb 2015 09:54:50 +1300 >Subject: [PATCH 30/31] backupkey: replace heimdal rsa key generation with > GnuTLS > >We use GnuTLS because it can reliably generate 2048 bit keys every time. > >Windows clients strictly require 2048, no more since it won't fit and no >less either. Heimdal would almost always generate a smaller key. > >Signed-off-by: Garming Sam <garming@catalyst.net.nz> >--- > source4/rpc_server/backupkey/dcesrv_backupkey.c | 126 +++++++++++++++--------- > 1 file changed, 82 insertions(+), 44 deletions(-) > >diff --git a/source4/rpc_server/backupkey/dcesrv_backupkey.c b/source4/rpc_server/backupkey/dcesrv_backupkey.c >index 5a2e8a4..ae4c871 100644 >--- a/source4/rpc_server/backupkey/dcesrv_backupkey.c >+++ b/source4/rpc_server/backupkey/dcesrv_backupkey.c >@@ -41,6 +41,12 @@ > #include "../libcli/security/security.h" > #include "librpc/gen_ndr/ndr_security.h" > #include "lib/crypto/arcfour.h" >+#include <gnutls/gnutls.h> >+#include <gnutls/x509.h> >+#if HAVE_GCRYPT_H >+#include <gcrypt.h> >+#endif >+ > > static const unsigned rsa_with_var_num[] = { 1, 2, 840, 113549, 1, 1, 1 }; > /* Equivalent to asn1_oid_id_pkcs1_rsaEncryption*/ >@@ -775,62 +781,67 @@ static WERROR bkrp_client_wrap_decrypt_data(struct dcesrv_call_state *dce_call, > return WERR_OK; > } > >+/* >+ * Strictly, this function no longer uses Heimdal in order to generate an RSA >+ * key, but GnuTLS. >+ * >+ * The resulting key is then imported into Heimdal's RSA structure. >+ * >+ * We use GnuTLS because it can reliably generate 2048 bit keys every time. >+ * Windows clients strictly require 2048, no more since it won't fit and no >+ * less either. Heimdal would almost always generate a smaller key. >+ */ > static WERROR create_heimdal_rsa_key(TALLOC_CTX *ctx, hx509_context *hctx, >- hx509_private_key *pk, RSA **_rsa) >+ hx509_private_key *pk, RSA **rsa) > { >- BIGNUM *pub_expo; >- RSA *rsa; > int ret; >- uint8_t *p0, *p; >+ uint8_t *p0 = NULL; >+ const uint8_t *p; > size_t len; > int bits = 2048; > int RSA_returned_bits; >+ gnutls_x509_privkey gtls_key; >+ WERROR werr; > >- *_rsa = NULL; >+ *rsa = NULL; > >- pub_expo = BN_new(); >- if(pub_expo == NULL) { >+ gnutls_global_init(); >+#ifdef HAVE_GCRYPT_H >+ DEBUG(3,("Enabling QUICK mode in gcrypt\n")); >+ gcry_control(GCRYCTL_ENABLE_QUICK_RANDOM, 0); >+#endif >+ ret = gnutls_x509_privkey_init(>ls_key); >+ if (ret != 0) { >+ gnutls_global_deinit(); > return WERR_INTERNAL_ERROR; > } > >- /* set the public expo to 65537 like everyone */ >- BN_set_word(pub_expo, 0x10001); >- >- rsa = RSA_new(); >- if(rsa == NULL) { >- BN_free(pub_expo); >- return WERR_INTERNAL_ERROR; >+ ret = gnutls_x509_privkey_generate(gtls_key, GNUTLS_PK_RSA, bits, 0); >+ if (ret != 0) { >+ werr = WERR_INTERNAL_ERROR; >+ goto done; > } > >- while (RSA_returned_bits != bits) { >- ret = RSA_generate_key_ex(rsa, bits, pub_expo, NULL); >- if(ret != 1) { >- RSA_free(rsa); >- BN_free(pub_expo); >- return WERR_INTERNAL_ERROR; >- } >- RSA_returned_bits = BN_num_bits(rsa->n); >- DEBUG(6, ("RSA_generate_key_ex returned %d Bits\n", RSA_returned_bits)); >- } >- BN_free(pub_expo); >+ /* No need to check error code, this SHOULD fail */ >+ gnutls_x509_privkey_export(gtls_key, GNUTLS_X509_FMT_DER, NULL, &len); > >- len = i2d_RSAPrivateKey(rsa, NULL); > if (len < 1) { >- RSA_free(rsa); >- return WERR_INTERNAL_ERROR; >+ werr = WERR_INTERNAL_ERROR; >+ goto done; > } > >- p0 = p = talloc_array(ctx, uint8_t, len); >- if (p == NULL) { >- RSA_free(rsa); >- return WERR_INTERNAL_ERROR; >+ p0 = talloc_size(ctx, len); >+ if (p0 == NULL) { >+ werr = WERR_NOMEM; >+ goto done; > } >+ p = p0; > >- len = i2d_RSAPrivateKey(rsa, &p); >- if (len < 1) { >- RSA_free(rsa); >- talloc_free(p0); >- return WERR_INTERNAL_ERROR; >+ ret = gnutls_x509_privkey_export(gtls_key, GNUTLS_X509_FMT_DER, p0, &len); >+ >+ if (ret != 0) { >+ werr = WERR_INTERNAL_ERROR; >+ goto done; > } > > /* >@@ -839,15 +850,42 @@ static WERROR create_heimdal_rsa_key(TALLOC_CTX *ctx, hx509_context *hctx, > */ > ret = hx509_parse_private_key(*hctx, &_hx509_signature_rsa_with_var_num , > p0, len, HX509_KEY_FORMAT_DER, pk); >- memset(p0, 0, len); >- talloc_free(p0); >- if (ret !=0) { >- RSA_free(rsa); >- return WERR_INTERNAL_ERROR; >+ >+ if (ret != 0) { >+ werr = WERR_INTERNAL_ERROR; >+ goto done; > } > >- *_rsa = rsa; >- return WERR_OK; >+ *rsa = d2i_RSAPrivateKey(NULL, &p, len); >+ TALLOC_FREE(p0); >+ >+ if (*rsa == NULL) { >+ hx509_private_key_free(pk); >+ werr = WERR_INTERNAL_ERROR; >+ goto done; >+ } >+ >+ RSA_returned_bits = BN_num_bits((*rsa)->n); >+ DEBUG(6, ("GnuTLS returned an RSA private key with %d bits\n", RSA_returned_bits)); >+ >+ if (RSA_returned_bits != bits) { >+ DEBUG(0, ("GnuTLS unexpectedly returned an RSA private key with %d bits, needed %d\n", RSA_returned_bits, bits)); >+ hx509_private_key_free(pk); >+ werr = WERR_INTERNAL_ERROR; >+ goto done; >+ } >+ >+ werr = WERR_OK; >+ >+done: >+ if (p0 != NULL) { >+ memset(p0, 0, len); >+ TALLOC_FREE(p0); >+ } >+ >+ gnutls_x509_privkey_deinit(gtls_key); >+ gnutls_global_deinit(); >+ return werr; > } > > static WERROR self_sign_cert(TALLOC_CTX *ctx, hx509_context *hctx, hx509_request *req, >-- >1.9.1 > > >From 73c3d4c05da31a51213387c8bb377f125898f9f3 Mon Sep 17 00:00:00 2001 >From: Garming Sam <garming@catalyst.net.nz> >Date: Fri, 13 Feb 2015 16:55:07 +1300 >Subject: [PATCH 31/31] torture-backupkey: Check the dcerpc call return code > before calling ndr pull > >Signed-off-by: Garming Sam <garming@catalyst.net.nz> >--- > source4/torture/rpc/backupkey.c | 8 +++++--- > 1 file changed, 5 insertions(+), 3 deletions(-) > >diff --git a/source4/torture/rpc/backupkey.c b/source4/torture/rpc/backupkey.c >index 53caf74..1a57bd2 100644 >--- a/source4/torture/rpc/backupkey.c >+++ b/source4/torture/rpc/backupkey.c >@@ -894,7 +894,6 @@ static bool test_RestoreGUID_v3(struct torture_context *tctx, > static bool test_RestoreGUID(struct torture_context *tctx, > struct dcerpc_pipe *p) > { >- enum ndr_err_code ndr_err; > struct dcerpc_binding_handle *b = p->binding_handle; > DATA_BLOB out_blob; > struct bkrp_client_side_unwrapped resp; >@@ -909,9 +908,12 @@ static bool test_RestoreGUID(struct torture_context *tctx, > torture_assert(tctx, r != NULL, "createRestoreGUIDStruct failed"); > torture_assert_ntstatus_ok(tctx, dcerpc_bkrp_BackupKey_r(b, tctx, r), "Restore GUID"); > out_blob.length = *r->out.data_out_len; >- ndr_err = ndr_pull_struct_blob(&out_blob, tctx, &resp, (ndr_pull_flags_fn_t)ndr_pull_bkrp_client_side_unwrapped); >- torture_assert_int_equal(tctx, NDR_ERR_CODE_IS_SUCCESS(ndr_err), 1, "Unable to unmarshall bkrp_client_side_unwrapped"); > torture_assert_werr_equal(tctx, r->out.result, WERR_OK, "Restore GUID"); >+ torture_assert_ndr_err_equal(tctx, >+ ndr_pull_struct_blob(&out_blob, tctx, &resp, >+ (ndr_pull_flags_fn_t)ndr_pull_bkrp_client_side_unwrapped), >+ NDR_ERR_SUCCESS, >+ "Unable to unmarshall bkrp_client_side_unwrapped"); > torture_assert_str_equal(tctx, (char*)resp.secret.data, secret, "Wrong secret"); > } else { > struct bkrp_BackupKey *r = createRetreiveBackupKeyGUIDStruct(tctx, p, 2, &out_blob); >-- >1.9.1 >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Raw
Flags:
kseeger
:
review?
(
abartlet
)
Actions:
View
Attachments on
bug 11097
: 10721 |
10808