Subject: [nfsv4] [PATCH 1/1] NFSv4.2 inter-server server-side copy with rpcsec_gss

From: <[email-masked]>
Date: Fri, 10 Jan 2014 16:27:19 -0500

From: Andy Adamson <[email-masked]>

This patch is based on the draft-ietf-nfsv4-minorversion2-19 RPCSEC_GSSv3
text for secure inter-server server-side copy, and is updated to use
draft-ietf-nfsv4-rpcsec-gssv3-06.

Signed-off-by: Andy Adamson <[email-masked]>
---
 dotx.d/spit_types.sh       |   13 +-
 nfsv42_back_references.xml |   15 ++
 nfsv42_middle_copy.xml     |  413 +++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 426 insertions(+), 15 deletions(-)

diff --git a/dotx.d/spit_types.sh b/dotx.d/spit_types.sh
index 40a2468..141a162 100755
--- a/dotx.d/spit_types.sh
+++ b/dotx.d/spit_types.sh
@@ -1327,8 +1327,6 @@ struct copy_from_auth_priv {
 	netloc4             cfap_destination;
 	/* the NFSv4 user name that the user principal maps to */
 	utf8str_mixed       cfap_username;
-	/* equal to seq_num of rpc_gss_cred_vers_3_t */
-	unsigned int        cfap_seq_num;
 };
 EOF
 	;;
@@ -1342,8 +1340,13 @@ struct copy_to_auth_priv {
 	netloc4              ctap_source;
 	/* the NFSv4 user name that the user principal maps to */
 	utf8str_mixed        ctap_username;
-	/* equal to seq_num of rpc_gss_cred_vers_3_t */
-	unsigned int         ctap_seq_num;
+	/* user principal RPCSEC_GSSv1 (or v2) handle shared
+	 * with the source server */
+	opaque               ctap_handle;
+	int                  ctap_handle_vers;
+	/* A nounce and a mic of the nounce using ctap_handle */
+	opaque               ctap_nounce;
+	opaque               ctap_nounce_mic;
 };
 EOF
 	;;
@@ -1356,8 +1359,6 @@ struct copy_confirm_auth_priv {
 	opaque              ccap_shared_secret_mic<>;
 	/* the NFSv4 user name that the user principal maps to */
 	utf8str_mixed       ccap_username;
-	/* equal to seq_num of rpc_gss_cred_vers_3_t */
-	unsigned int        ccap_seq_num;
 };
 EOF
 
diff --git a/nfsv42_back_references.xml b/nfsv42_back_references.xml
index 08a2880..20714ea 100644
--- a/nfsv42_back_references.xml
+++ b/nfsv42_back_references.xml
@@ -41,6 +41,21 @@
 	      target="ftp://ftp.isi.edu/in-notes/rfc5664.txt"/>
     </reference>
 
+    <reference anchor='rpcsec_gssv3'>
+      <front>
+        <title>Remote Procedure Call (RPC) Security Version 3</title>
+        <author initials="W." surname="Adamson" fullname="W. Adamson">
+          <organization>NetApp</organization>
+        </author>
+        <author initials="N." surname="Williams" fullname="N. Williams">
+          <organization>Cryptonector</organization>
+        </author>
+        <date year="2013" month="October"/>
+      </front>
+      <format type="TXT"
+              target="http://tools.ietf.org/id/draft-ietf-nfsv4-rpcsec-gssv3-06.txt"/>
+    </reference>
+
     <reference anchor='NFSv42xdr'>
       <front>
 	<title>Network File System (NFS) Version 4 Minor Version 2 External Data Representation Standard (XDR) Description</title>
diff --git a/nfsv42_middle_copy.xml b/nfsv42_middle_copy.xml
index 9de4a43..424e18d 100644
--- a/nfsv42_middle_copy.xml
+++ b/nfsv42_middle_copy.xml
@@ -5,14 +5,12 @@
   <section title="Introduction">
     <t>
       The server-side copy feature provides a mechanism for
-      the NFS client to perform a file copy on the server without
-      the data being transmitted back and forth over the network.
+      the NFS client to perform a file copy on a server or between two
+      servers without the data being
+      transmitted back and forth over the network through the NFS client.
       Without this feature, an NFS client copies data from one location
-      to another by reading the data from the server over the network, and
-      then writing the data back over the network to the server. Using this
-      server-side copy operation, the client is able to instruct the server
-      to copy the data locally without the data being sent back and forth
-      over the network unnecessarily.
+      to another by reading the data from the source server over the network, and
+      then writing the data back over the network to the destiniation server.
     </t>
 
     <t>
@@ -575,7 +573,14 @@
       operations described in this chapter are REQUIRED to implement the
       mechanism described in <xref target="sec:SSC-with-rpc" />,
       and to support rejecting COPY_NOTIFY requests that do not use
-      RPCSEC_GSS with privacy.  This requirement to implement is not
+      RPCSEC_GSS with privacy.
+      If the server-to-server copy protocol is ONC RPC
+      based, the servers are also REQUIRED to implement
+      <xref target="rpcsec_gssv3" /> including the RPCSEC_GSSv3
+      copy_to_auth, copy_from_auth, and copy_confirm_auth structured
+      privileges.
+
+      This requirement to implement is not
       a requirement to use; for example, a server may depending on
       configuration also allow COPY_NOTIFY requests that use only AUTH_SYS.
     </t>
@@ -632,7 +637,397 @@
         </t>
       </section>
 
-      <section title="Inter-Server Copy via ONC RPC" anchor="sec:SSC-with-rpc">
+      <section title="Inter-Server Copy vi ONC RPC with RPCSEC_GSSv3">
+        <t>
+         When the client sends a COPY_NOTIFY to the source server to expect
+         the destination to attempt to copy data from the source server, it is
+         expected that this copy is being done on behalf of the principal
+         (called the "user principal") that sent the RPC request that encloses
+         the COMPOUND procedure that contains the COPY_NOTIFY operation.  The
+         user principal is identified by the RPC credentials.  A mechanism
+         that allows the user principal to authorize the destination server to
+         perform the copy in a manner that lets the source server properly
+         authenticate the destination's copy, and without allowing the
+         destination to exceed its authorization is necessary.
+        </t>
+        <t>
+         An approach that sends delegated credentials of the client's user
+         principal to the destination server is not used for the following
+         reasons.  If the client's user delegated its credentials, the
+         destination would authenticate as the user principal.  If the
+         destination were using the NFSv4 protocol to perform the copy, then
+         the source server would authenticate the destination server as the
+         user principal, and the file copy would securely proceed.  However,
+         this approach would allow the destination server to copy other files.
+         The user principal would have to trust the destination server to not
+         do so.  This is counter to the requirements, and therefore is not
+         considered.
+        </t>
+        <t>
+         Instead, we employ a combination of two features of the
+         RPCSEC_GSSv3 <xref target="rpcsec_gssv3" /> protocol:
+         compound authentication and RPC application defined structured
+         privilege assertions. The combination of these features allows the
+         destination server to authenticate to the source server as acting on
+         behalf of the user prinicpal, and to authorize the destination server
+         to perform READs of the file to be copied from the source on behalf
+         of the user principal. Once the copy is complete, the client can
+         destroy the RPCSEC_GSSv3 handles to end the source and destination
+         servers authorization to copy. 
+        </t>
+        <t>
+         RPCSEC_GSSv3 introduces the notion of RPC application defined
+         structured privileges.  We define three structured privileges
+	 that work in tandum to authorize the copy:
+        </t>
+
+        <t>
+          <list style="hanging">
+
+            <t hangText="copy_from_auth:">
+              A user principal is authorizing a source principal
+              ("nfs@&lt;source&gt;") to allow a destination principal
+              ("nfs@&lt;destination&gt;") to setup the copy_confirm_auth
+              privilege required to copy a file from the source to the
+              destination on behalf of the user principal.
+              This privilege is established on the source server before
+	      the user principal sends a COPY_NOTIFY operation to the source
+	      server, and the resultant RPCSEC_GSSv3 context is used to secure
+	      the COPY_NOTIFY operation.
+
+	      <vspace blankLines="1" />
+	      <?rfc include='autogen/copy_from_auth.xml'?>
+	      <vspace blankLines="1" />
+
+	      cfp_shared_secret is a secret value the user principal generates.
+            </t>
+
+            <t hangText="copy_to_auth:">
+              A user principal is authorizing a destination principal
+              ("nfs@&lt;destination&gt;") to setup a copy_confirm_auth
+              privilege with a source principal ("nfs@&lt;source&gt;")
+	      to allow it to copy a file from the source to the
+              destination on behalf of the user principal.
+              This privilege is established on the destination server before
+	      the user principal sends a COPY operation to the destination
+	      server, and the resultant RPCSEC_GSSv3 context is used to
+	      secure the COPY operation.
+
+	      <vspace blankLines="1" />
+	      <?rfc include='autogen/copy_to_auth.xml'?>
+	      <vspace blankLines="1" />
+
+	      ctap_shared_secret is the secret value the user principal
+	      generated and was used to establish the copy_from_auth privilege
+	      with the source principal.
+
+	      ctap_handle, ctap_handle_vers, ctap_nounce and ctap_nounce_mic are
+              used to construct the compound authentication portion of the 
+	      copy_confirm_auth RPCGSS_GSSv3 context between the destination
+	      server and the source server.
+            </t>
+
+            <t hangText="copy_confirm_auth:">
+              A destination principal ("nfs@&lt;destination&gt;") is
+	      confirming with the source principal ("nfs@&lt;source&gt;")
+	      that it is authorized to copy data from the source. Note that
+	      besides the rpc_gss3_privs payload
+	      (struct copy_confirm_auth_priv), the copy_confirm_auth
+	      RPCSEC_GSS3_CREATE message also contains an rpc_gss3_gss_binding
+	      payload so that the copy is done on behalf of the user principal.
+              This privilege is established on the destination server before
+	      the file is copied from the source to the destination. The
+	      resultant RPCSEC_GSSv3 context is used to secure the READ
+	      operations from the source to the destination server.
+
+	      <vspace blankLines="1" />
+	      <?rfc include='autogen/copy_confirm_auth.xml'?>
+	      <vspace blankLines="1" />
+            </t>
+
+          </list>
+        </t>
+      <section title="Establishing a Security Context">
+        <t>
+         When the user principal wants to COPY a file between two servers, if
+         it has not established copy_from_auth and copy_to_auth privileges on
+         the servers, it establishes them:
+        </t>
+        <t>
+          <list style="symbols">
+            <t>
+             As noted in <xref target="rpcsec_gssv3" /> the client uses an
+             existing RPCSEC_GSSv1 (or v2) context termed the "parent" handle
+	     to establish and protect RPCSEC_GSSv3 exchanges.
+	     The copy_from_auth privilege
+	     will use the context established between the user principal and
+	     the source server used to OPEN the source file as the
+	     RPCSEC_GSSv3 parent handle. The copy_to_auth privilege will use
+	     the context established between the user principal and the
+	     destination server used to OPEN the destination file as the
+	     RPCSEC_GSSv3 parent handle.
+            </t>
+
+            <t>
+             The user principal generates a secret it will share with the two
+             servers.  This shared secret will be placed in the
+             cfap_shared_secret and ctap_shared_secret fields of the
+             appropriate privilege data types, copy_from_auth_priv and
+             copy_to_auth_priv.  Because of this shared_secret
+             the RPCSEC_GSS3_CREATE control messages for copy_from_auth and
+             copy_to_auth MUST use a QOP of rpc_gss_svc_privacy.
+            </t>
+
+            <t>
+             An instance of copy_from_auth_priv is filled in with the shared
+             secret, the destination server, and the NFSv4 user id of the user
+             principal and is placed in rpc_gss3_create_args
+             assertions[0].assertion.privs.privilege. The string
+             "copy_from_auth" is placed in assertions[0].assertion.privs.name.
+             The field assertions[0].critical is set to TRUE. The source server
+             unwraps the rpc_gss_svc_privacy RPCSEC_GSS3_CREATE payload and
+             verifies that the NFSv4 user id being asserted matches the source
+             server's mapping of the user principal.  If it does, the privilege
+             is established on the source server as:
+             &lt;"copy_from_auth", user id, destination&gt;.  The field
+             "handle" in a successful reply is the RPCSEC_GSSv3 "child" handle
+             that the client will use on COPY_NOTIFY requests to the source
+	     server involving the destination server.
+             granted_assertions[0].assertion.privs.name will be equal to
+             "copy_from_auth".
+	    </t>
+
+            <t>
+             An instance of copy_to_auth_priv is filled in with the shared
+             secret, the cnr_source_server list returned by COPY_NOTIFY, and
+             the NFSv4 user id of the user
+             principal. A nounce is created, and GSS_MIC() is inovked on the
+	     nounce using the RPCSEC_GSSv1 (or v2) context shared between
+	     user prinicpal and the source server. The nounce, nounce MIC,
+	     context handle used to create the nounce MIC, and the context
+	     handle version are added to the copy_to_auth_priv instance which
+	     is placed in 
+             rpc_gss3_create_args assertions[0].assertion.privs.privilege. The
+	     string "copy_to_auth"
+             is placed in assertions[0].assertion.privs.name. The
+             field assertions[0].critical is set to TRUE. The destination server
+             unwraps the rpc_gss_svc_privacy RPCSEC_GSS3_CREATE payload and
+             verifies that the NFSv4 user id being asserted matches the
+	     destination server's mapping of the user principal.  If it does,
+	     the privilege is established on the destination server as:
+             &lt;"copy_to_auth", user id, source list, nounce, nounce MIC,
+	     context handle, handle version&gt;.  The field 
+             "handle" in a successful reply is the RPCSEC_GSSv3 "child" handle
+             that the client will use on COPY requests to the destination
+	     server involving the source server.
+             granted_assertions[0].assertion.privs.name will be equal to
+             "copy_to_auth".
+            </t>
+          </list>
+        </t>
+	<t>
+	 As noted in <xref target="rpcsec_gssv3" />
+	 section 2.3.1 "Create Request", both the client and the source
+	 server should associate the RPCSEC_GSSv3 "child" handle with the
+	 parent RPCSEC_GSSv1 (or v2) handle used to create the RPCSEC_GSSv3
+	 child handle.
+        </t>
+      </section>
+
+      <section title="Starting a Secure Inter-Server Copy">
+	<t>
+         When the client sends a COPY_NOTIFY request to the source server, it
+         uses the privileged "copy_from_auth" RPCSEC_GSSv3 handle.
+         cna_destination_server in COPY_NOTIFY MUST be the same as
+         cfap_destination specified in copy_from_auth_priv.  Otherwise,
+         COPY_NOTIFY will fail with NFS4ERR_ACCESS.  The source server
+         verifies that the privilege
+         &lt;"copy_from_auth", user id, destination&gt;
+         exists, and annotates it with the source filehandle, if the user
+         principal has read access to the source file, and if administrative
+         policies give the user principal and the NFS client read access to
+         the source file (i.e., if the ACCESS operation would grant read
+         access).  Otherwise, COPY_NOTIFY will fail with NFS4ERR_ACCESS.
+        </t>
+
+	<t>
+         When the client sends a COPY request to the destination server, it
+         uses the privileged "copy_to_auth" RPCSEC_GSSv3 handle.
+         ca_source_server list in COPY MUST be the same as ctap_source list
+         specified in copy_to_auth_priv.  Otherwise, COPY will fail
+         with NFS4ERR_ACCESS.  The destination server verifies that the
+         privilege &lt;"copy_to_auth", user id, source list, nounce, nounce MIC,
+         context handle, handle version&gt;
+         exists, and annotates it with the source and destination filehandles.
+	 If the COPY returns a wr_callback_id, then this is an asynchronous
+	 copy and the wr_callback_id must also must be annotated to the
+	 copy_to_auth privilege.  If the client has
+         failed to establish the "copy_to_auth" privilege it will reject the
+         request with NFS4ERR_PARTNER_NO_AUTH.
+        </t>
+
+	<t>
+         If either the COPY_NOTIFY, or the COPY operations fail, the associated
+         "copy_from_auth" and "copy_to_auth" RPCSEC_GSSv3 handles MUST be
+         destroyed.
+        </t>
+      </section>
+
+      <section title="Securing ONC RPC Server-to-Server Copy Protocols">
+	<t>
+         After a destination server has a "copy_to_auth" privilege established
+         on it, and it receives a COPY request, if it knows it will use an ONC
+         RPC protocol to copy data, it will establish a "copy_confirm_auth"
+         privilege on the source server prior to responding to the COPY
+	 operation as follows:
+        </t>
+        <t>
+          <list style="symbols">
+            <t>
+             Before establishing an RPCSEC_GSSv3 context, a parent context
+             needs to exist between nfs@&lt;destination&gt; as the
+             initiator principal, and nfs@&lt;source&gt; as the target principal.
+             If NFS is to be used as the copy protocol, this means that the
+             destiniation server must mount the source server using RPCSEC_GSS.
+	    </t>
+
+            <t>
+             An instance of copy_confirm_auth_priv is filled in with information
+             from the established "copy_to_auth" privilege. The value of the
+	     field ccap_shared_secret_mic is a GSS_GetMIC() of the 
+	     ctap_shared_secret in the copy_to_auth privilege using the
+	     parent handle context.
+	     The field ccap_username is the mapping of the user principal to
+	     an NFSv4 user name ("user"@"domain" form), and MUST be the same
+	     as the ctap_username in the copy_to_auth privilege.
+             The copy_confirm_auth_priv instance is placed in
+             rpc_gss3_create_args assertions[0].assertion.privs.privilege.
+             The string "copy_confirm_auth" is placed in
+	     assertions[0].assertion.privs.name.  The field
+	     assertions[0].critical is set to TRUE.  
+	    </t>
+
+            <t>
+	     The copy_confirm_auth RPCSEC_GSS3_CREATE call also includes
+	     a compound authentication component. The rpc_gss3_gss_binding
+	     fields are filled in with information from the estalished
+	     "copy_to_auth" privilege. The ctap_handle_vers, ctap_handle,
+	     ctap_nounce, and ctap_nounce_mic are assigned to the vers, handle,
+	     nounce, and mic fields of an rpc_gss3_gss_binding instance
+	     respectively.
+	    </t>
+
+	    <t>
+	     The RPCSEC_GSS3_CREATE copy_from_auth message is sent to the
+	     source server with a QOP of rpc_gss_svc_privacy. The source
+	     server unwraps the rpc_gss_svc_privacy RPCSEC_GSS3_CREATE
+	     payload and verifies the cap_shared_secret_mic by calling
+	     GSS_VerifyMIC() using the parent context on the
+	     cfap_shared_secret from the established "copy_from_auth"
+	     privilege, and verifies the that the ccap_username equals
+	     the cfap_username.
+	     The source server then locates the ctap_handle in it's GSS
+	     context cache and verifies that the handle belongs to the
+	     user principal that maps to the ccap_username and that the
+	     cached handle version equals ctap_handle_vers. The
+	     ctap_nounce_mic is verified by calling GSS_VerifyMIC()
+	     on the ctap_nounce using the cached handle context.
+	     If all verification succeeds, the "copy_confirm_auth" privilege
+	     is established on the source server as &lt; "copy_confirm_auth",
+	     shared_secret_mic, user id, nounce, nounce MIC, context handle,
+	     context handle version&gt;, and the resultant child
+	     handle is noted to be acting on behalf of the user principal.
+	     If the source server fails to verify either the
+	     privilege or the compound_binding, the COPY operation will be
+             rejected with NFS4ERR_PARTNER_NO_AUTH.
+	    </t>
+
+	    <t>
+	      All subsequent ONC RPC requests sent from the destination to
+	      copy data from the source to the destination will use the
+	      RPCSEC_GSSv3 handle returned by the source's RPCSEC_GSS3_CREATE
+	      response. Note that as per the Compound Authenticaion section of
+	      <xref target="rpcsec_gssv3" />
+	      the resultant RPCSEC_GSSv3 context handle is bound to
+	      the user principal RPCSEC_GSS context and so it MUST be treated by
+	      servers as authenticating the user principal.
+	    </t>
+
+          </list>
+        </t>
+
+        <t>
+	   Note that the use of the "copy_confirm_auth" privilege accomplishes
+	   the following:
+
+          <list style="symbols">
+            <t>
+	     if a protocol like NFS is being used, with export policies,
+	     export policies can be overridden in case the destination
+	     server as-an-NFS-client is not authorized
+	   </t>
+
+	   <t>
+            manual configuration to allow a copy relationship between the
+            source and destination is not needed.
+	   </t>
+          </list>
+        </t>
+
+      </section>
+      <section title="Finishing or Stoping a Secure Inter-Server Copy">
+        <t>
+	 Under normal operation, the client MUST destroy the copy_from_auth
+	 and the copy_to_auth RPCSEC_GSSv3 handle once the COPY operation
+	 returns for a synchronous inter-server copy or a CB_OFFLOAD 
+	 reports the result of an asynchronous copy.
+        </t>
+
+        <t>
+	 The copy_confirm_auth privilege and compound authentication
+	 RPCSEC_GSSv3 handle is constructed from information held by the
+	 copy_to_auth privilege, and MUST be destroyed by the destination
+         server (via an RPCSEC_GSS3_DESTROY call) when the copy_to_auth
+         RPCSEC_GSSv3 handle is destroyed.
+        </t>
+
+	<t>
+         If the client sends a OFFLOAD_REVOKE to the source server to rescind
+         the destination server's synchronous copy privilege,
+         it uses the privileged
+         "copy_from_auth" RPCSEC_GSSv3 handle and the cra_destination_server
+         in OFFLOAD_REVOKE MUST be the same as the name of the destination
+         server specified in copy_from_auth_priv.  The source server will then
+         delete the &lt;"copy_from_auth", user id, destination&gt; privilege and
+         fail any subsequent copy requests sent under the auspices of this
+         privilege from the destination server. The client MUST destroy both
+         the "copy_from_auth" and the "copy_to_auth" RPCSEC_GSSv3 handles.
+        </t>
+
+        <t>
+         If the client sends a OFFLOAD_STATUS to the destination server to
+         check on the status of an asynchronous copy, it uses the privileged
+         "copy_to_auth" RPCSEC_GSSv3 handle and the osa_stateid in OFFLOAD_STATUS
+         MUST be the same as the wr_callback_id specified in the "copy_to_auth"
+         privilege stored on the destiniation server.
+        </t>
+
+        <t>
+         If the client sends a OFFLOAD_ABORT to the destination server to
+         cancel an asynchronous copy, it uses the privileged "copy_to_auth"
+         RPCSEC_GSSv3 handle and the oaa_stateid in OFFLOAD_ABORT MUST be
+         the same as the wr_callback_id specified in the "copy_to_auth"
+         privilege stored on the destiniation server. The destiniation server
+         will then delete the &lt;"copy_to_auth", user id, source list,
+         nounce, nounce MIC, context handle, handle version&gt; privilege and
+         the associated "copy_confirm_auth" RPCSEC_GSSv3 handle.
+         The client MUST destroy both the copy_to_auth and
+         copy_from_auth RPCSEC_GSSv3 handles.
+        </t>
+
+      </section>
+      </section>
+      <section title="Inter-Server Copy via ONC RPC without RPCSEC_GSSv3" anchor="sec:SSC-with-rpc">
         <t>
           In the absence of a strong security mechanism designed for the
           purpose, the challenge is how the source server
-- 
1.7.10.2 (Apple Git-33)