[PATCH 4/4] s4-backupkey: create new x509 after expiry date

Arvid Requate requate at univention.de
Tue Jul 8 10:36:03 MDT 2014


Since [MS-BKRP] 2.2.1 specifies a lifetime of one year for the ClientWrap x509 
certificate we should probably check it's validity, given that section 3.2.3.1 
specifies that the client MUST validate the data returned by the server. If the 
certificate is expired we better generate a new one.

G$BCKUPKEY_PERFERRED is then updated to point to the currently valid 
certificate, as described in [MS-BKRP] 3.1.4.1.3.

Signed-off-by: Arvid Requate <requate at univention.de>
---
 source4/rpc_server/backupkey/dcesrv_backupkey.c | 212 
++++++++++++++++++------
 1 file changed, 158 insertions(+), 54 deletions(-)

diff --git a/source4/rpc_server/backupkey/dcesrv_backupkey.c 
b/source4/rpc_server/backupkey/dcesrv_backupkey.c
index 6699b78..59895b2 100644
--- a/source4/rpc_server/backupkey/dcesrv_backupkey.c
+++ b/source4/rpc_server/backupkey/dcesrv_backupkey.c
@@ -101,10 +101,46 @@ static NTSTATUS set_lsa_secret(TALLOC_CTX *mem_ctx,
                           "(&(cn=%s)(objectclass=secret))",
                           ldb_binary_encode_string(mem_ctx, name2));
 
-       if (ret != LDB_SUCCESS ||  res->count != 0 ) {
-               DEBUG(2, ("Secret %s already exists !\n", name2));
+       if (ret != LDB_SUCCESS) {
+               talloc_free(msg);
+               return NT_STATUS_INTERNAL_ERROR;
+       }
+       if (res->count != 0 ) {
+               if (strcmp(name, "BCKUPKEY_PREFERRED")) {
+                       DEBUG(2, ("Secret %s already exists !\n", name2));
+                       talloc_free(msg);
+                       return NT_STATUS_OBJECT_NAME_COLLISION;
+               }
+
+               if (res->count > 1) {
+                       DEBUG(2, ("BCKUPKEY_PREFERRED collision\n"));
+                       return NT_STATUS_INTERNAL_DB_CORRUPTION;
+               }
+
+               DEBUG(6, ("Updating BCKUPKEY_PREFERRED\n"));
+               msg->dn = res->msgs[0]->dn;
+
+               val.data = secret->data;
+               val.length = secret->length;
+               struct ldb_message_element *el;
+               ret = ldb_msg_add_value(msg, "currentValue", &val, &el);
+               if (ret != LDB_SUCCESS) {
+                       talloc_free(msg);
+                       return NT_STATUS_NO_MEMORY;
+               }
+               el->flags = LDB_FLAG_MOD_REPLACE;
+
+               ret = dsdb_modify(ldb, msg, 0);
+               if (ret != LDB_SUCCESS) {
+                       DEBUG(2,("Failed to update secret record %s: %s\n",
+                               ldb_dn_get_linearized(msg->dn),
+                               ldb_errstring(ldb)));
+                       talloc_free(msg);
+                       return NT_STATUS_ACCESS_DENIED;
+               }
+
                talloc_free(msg);
-               return NT_STATUS_OBJECT_NAME_COLLISION;
+               return NT_STATUS_OK;
        }
 
        /*
@@ -1199,14 +1235,101 @@ static WERROR generate_bkrp_cert(TALLOC_CTX *ctx, 
struct dcesrv_call_state *dce_
        return WERR_OK;
 }
 
+static int validate_bkrp_exported_RSA_key_pair(struct 
bkrp_exported_RSA_key_pair *keypair)
+{
+       hx509_context hctx;
+       hx509_cert cert;
+
+       hx509_context_init(&hctx);
+       hx509_cert_init_data(hctx, keypair->cert.data, keypair->cert.length, 
&cert);
+       if (time(NULL) > hx509_cert_get_notAfter(cert)) {
+               DEBUG(6, ("Certificate is expired\n"));
+               return HX509_CERT_USED_AFTER_TIME;
+       };
+
+       return 0;
+};
+
+static WERROR fetch_bkrp_exported_RSA_key_pair(TALLOC_CTX *mem_ctx, struct 
ldb_context *ldb_ctx,
+       struct GUID *guid, struct bkrp_exported_RSA_key_pair *keypair)
+{
+       char *guid_string;
+       char *cert_secret_name;
+       NTSTATUS status;
+       DATA_BLOB secret;
+       enum ndr_err_code ndr_err;
+
+       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;
+       }
+
+       cert_secret_name = talloc_asprintf(mem_ctx,
+                                               "BCKUPKEY_%s",
+                                               guid_string);
+       status = get_lsa_secret(mem_ctx,
+                               ldb_ctx,
+                               cert_secret_name,
+                               &secret);
+       if (!NT_STATUS_IS_OK(status)) {
+               return WERR_FILE_NOT_FOUND;
+       }
+
+       if (secret.length != 0) {
+               ndr_err = ndr_pull_struct_blob(&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;
+               }
+
+               if (validate_bkrp_exported_RSA_key_pair(keypair)) {
+                       return WERR_FILE_NOT_FOUND;
+               };
+
+               return WERR_OK;
+       } else {
+               DEBUG(10, ("No or broken secret called %s\n", 
cert_secret_name));
+               return WERR_FILE_NOT_FOUND;
+       }
+}
+
+static WERROR new_bkrp_cert(struct dcesrv_call_state *dce_call, TALLOC_CTX 
*mem_ctx,
+       struct ldb_context *ldb_ctx, DATA_BLOB *secret)
+{
+       NTSTATUS status;
+       WERROR werr;
+
+       struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx;
+       char *dn = talloc_asprintf(mem_ctx, "CN=%s",
+                                       lpcfg_realm(lp_ctx));
+
+       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",
+                       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;
+       }
+}
+
 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;
-       char *guid_string;
        DATA_BLOB secret;
-       enum ndr_err_code ndr_err;
        NTSTATUS status;
+       WERROR werr;
+       struct bkrp_exported_RSA_key_pair keypair;
 
        /*
         * here we basicaly need to return our certificate
@@ -1221,23 +1344,9 @@ static WERROR bkrp_do_retrieve_client_wrap_key(struct 
dcesrv_call_state *dce_cal
                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);
+                       werr = new_bkrp_cert(dce_call, mem_ctx, ldb_ctx, 
&secret);
                        if (!W_ERROR_IS_OK(werr)) {
-                               return WERR_INVALID_PARAMETER;
-                       }
-                       status = get_lsa_secret(mem_ctx,
-                                       ldb_ctx,
-                                       "BCKUPKEY_PREFERRED",
-                                       &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;
+                               return werr;
                        }
                } else {
                        /* In theory we should NEVER reach this point as it
@@ -1248,47 +1357,42 @@ static WERROR bkrp_do_retrieve_client_wrap_key(struct 
dcesrv_call_state *dce_cal
        }
 
        if (secret.length != 0) {
-               char *cert_secret_name;
-
                status = GUID_from_ndr_blob(&secret, &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;
-               }
-
-               cert_secret_name = talloc_asprintf(mem_ctx,
-                                                       "BCKUPKEY_%s",
-                                                       guid_string);
-               status = get_lsa_secret(mem_ctx,
-                                       ldb_ctx,
-                                       cert_secret_name,
-                                       &secret);
-               if (!NT_STATUS_IS_OK(status)) {
-                       return WERR_FILE_NOT_FOUND;
-               }
+               werr = fetch_bkrp_exported_RSA_key_pair(mem_ctx, ldb_ctx,
+                                                       &guid, &keypair);
 
-               if (secret.length != 0) {
-                       struct bkrp_exported_RSA_key_pair keypair;
-                       ndr_err = ndr_pull_struct_blob(&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;
+               if (W_ERROR_EQUAL(werr, WERR_FILE_NOT_FOUND)) {
+                       /* Ok we can be in this case if the cert was invalid 
or not found */
+                       werr = new_bkrp_cert(dce_call, mem_ctx, ldb_ctx, 
&secret);
+                       if (!W_ERROR_IS_OK(werr)) {
+                               return werr;
                        }
-                       *(r->out.data_out_len) = keypair.cert.length;
-                       *(r->out.data_out) = talloc_memdup(mem_ctx, 
keypair.cert.data, keypair.cert.length);
-                       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;
+
+                       if (secret.length != 0) {
+                               status = GUID_from_ndr_blob(&secret, &guid);
+                               if (!NT_STATUS_IS_OK(status)) {
+                                       return WERR_FILE_NOT_FOUND;
+                               }
+
+                               werr = 
fetch_bkrp_exported_RSA_key_pair(mem_ctx, ldb_ctx,
+                                                                       &guid, 
&keypair);
+                               if (!W_ERROR_IS_OK(werr)) {
+                                       return werr;
+                               }
+                       }
+               }
+               if (!W_ERROR_IS_OK(werr)) {
+                       return werr;
                }
+
+               *(r->out.data_out_len) = keypair.cert.length;
+               *(r->out.data_out) = talloc_memdup(mem_ctx, keypair.cert.data, 
keypair.cert.length);
+               W_ERROR_HAVE_NO_MEMORY(*(r->out.data_out));
+               return WERR_OK;
        } else {
                DEBUG(10, ("No secret BCKUPKEY_PREFERRED\n"));
                return WERR_FILE_NOT_FOUND;
-- 
2.0.0.rc2



More information about the samba-technical mailing list