Sun 企業辯證機制使用指南

第 8章 以 RPCSEC_GSS 的安全網路程式編寫

執行網路操作的應用程式通常必須確定其在網路上的交換是安全的。RPCSEC_GSS 應用程式程式編寫介面 (API) 允許開發者利用各種安全機制,包括 SEAM 及 Kerberos V5。同樣重要地,RPCSEC_GSS 也包括整合性及保密性服務,以提供辯證以外的防護措施。雖然 RPCSEC_GSS 既非 SEAM 的一部份,也不是專門針對它而寫的,但是想要在其應用程式中利用 Kerberos V5 的程式設計師會發現 RPCSEC_GSS 非常有幫助。事實上,因為 RPCSEC_GSS 與機制無關,沒有使用 SEAM/Kerberos V5 作為安全機制但又想利用其保密性及整合性特點的開發者,亦應考慮是否要使用它。

本章假設您已經非常熟悉 RPC 的程式寫作,請參見 ONC+ 開發者使用指南中有關 RPC 的資訊。此外,本章僅提供為一個概觀,如需 RPCSEC_GSS 各種要點的資訊,如功能或資料結構等,請參見 rpcsec_gss(3N) 線上援助頁,或是本章所述的任何功能之線上援助頁。

本章所涵蓋的主題如下所示﹕

安全性質

本節將說明 RPCSEC_GSS API 的開發及性質。

RPCSEC_GSS 之前的安全

RPC 所支援的最早的安全性質之一就是 AUTH_SYS(亦稱為 AUTH_UNIX)。AUTH_SYS 可以提供一張 UNIX 式的證書,利用使用者及群組識別碼來辨識一份訊息的發件人及收件人身份。AUTH_SYS 很容易實行。不過也很容易被人避開,因為它無法提供真正的辯證 - 亦即一個伺服器無法確認一個客戶端實際上就是它所宣稱的身份。因此在 AUTH_SYS 之下便很容易偽造一個網路要求。

在 AUTH_SYS 之後不久又出現了另外一種安全性質﹕AUTH_DES。AUTH_DES 是以一個共用的密鑰辯證為基礎的 - 它使用一種 Diffie-Hellman 密鑰交換來在客戶端的專用密鑰以及一個伺服器的公開密鑰之間產生一個共用密鑰。共用密鑰便被用來加密一個 DES 作業階段密鑰,伺服器會將其解密以建立一個作業階段。

雖然 AUTH_DES 要比 AUTH_SYS 大有進步,它仍然有某些限制,因此不能廣為使用。許多人主要反對的理由在於,以今天的加密標準而言,其密鑰的大小不夠。

終於最後又產生了另一種 RPC 安全性質。AUTH_KERB 是以 Kerberos V4 為基礎的,可以比 AUTH_DES 或 AUTH_SYS 提供較佳的安全防護。不過它還是有被利用的可能。

如需有關這些安全性質的詳細資訊,請參見 ONC+ 開發者使用指南

整合性及保密性﹕GSS-API

為了改善安全上的防護,另外新增了兩項通用安全標準﹕API 或 GSS-API 來作為新的網路層級。GSS-API 架構在辯證之外有兩種額外的安全服務


註解 -

目前 GSS-API 尚未被公開。不過某些特定的 GSS-API 功能可藉由 RPCSEC_GSS 功能而變得“可見” - 亦即以一種“不透明”的方式來操控它們。程式設計師不需要直接考量其數值。


RPCSEC_GSS API

RPCSEC_GSS 安全性質允許 ONC RPC 應用程式利用 GSS-API 的功能。RPCSEC_GSS 位於 GSS-API 層級“之上”,如下所示﹕

圖 8-1 GSS-API 及 RPCSEC_GSS 安全層級

Graphic

ONC RPC 應用程式可以利用 RPCSEC_GSS 的程式編寫介面來指定﹕

機制

一種安全的樣式。每一種安全機制都可以提供不同類型的資料保護,以及一或多層的資料保護。這__指的是 GSS-API 所支援的任何安全機制(Kerberos V5、RSA 共用密鑰等等)。

安全服務

保密性或是整合性(或兩者皆否)。預設值為整合性。此項服務與機制無關。

QOP

保護品質。QOP 指定要用來實施保密性或整合性服務的加密運算式類型。每一種安全機制都有一或多個相關的 QOP。

應用程式可以透過 RPCSEC_GSS 所提供的函數來取得有效的 QOP 及機制清單。(請參見 "其他函數"。)開發者應該避免硬性將機制及 QOP 編碼入其應用程式,以免使用新的或不同的機制及 QOP 來修改應用程式。


註解 -

歷史上來說,“安全性質”及“辯證性質”指的是相同的東西。自從 RPCSEC_GSS 問市之後,現在“性質”就有了一種較為不同的意義。性質可以包括一項服務(整合性或保密性)及辯證,雖然目前只有 RPCSEC_GSS 這一種性質是如此。


ONC RPC 應用程式可以使用 RPCSEC_GSS 來建立與同層的安全上下文、交換資料、並且損毀上下文,正如與其他性質一樣。一旦建立上下文之後,應用程式就能為每個傳送的資料單位變更 QOP 及服務。

如需有關 RPCSEC_GSS 的詳細資訊,包括 RPCSEC_GSS 資料類型,請參見 rpcsec_gss(3N) 線上援助頁。

RPCSEC_GSS 常式

表 8-1 對 RPCSEC_GSS 指令做一個摘要性的說明。其目的在於提供 RPCSEC_GSS 函數的一般性概觀,而不是有關每一個函數的特定說明。如需有關每一個函數的詳細資訊,請參見其線上援助頁或是 rpcsec_gss(3N) 線上援助頁所提供的概觀,其中包括一份 RPCSEC_GSS 資料結構的清單。

表 8-1 RPCSEC_GSS 函數
動作函數輸入輸出
 建立一個安全的上下文rpc_gss_seccreate() CLIENT 控點、主管名稱、機制、QOP、服務類型AUTH 控點
 變更 QOP,上下文的服務類型rpc_gss_set_defaults() 舊的 QOP,服務 新的 QOP,服務
 顯示在安全傳送之前最大的資料大小rpc_gss_max_data_length() 傳輸所允許的最大的資料大小 最大的事先傳送資料大小
 顯示在安全傳送之前最大的資料大小rpc_gss_svc_max_data_length() 傳輸所允許的最大的資料大小 最大的事先傳送資料大小
 設定所代表的伺服器主管名稱rpc_gss_set_svc_name() 主管名稱、RPC 程式、版本編號 TRUE 如果成功的話
 提取呼叫者的證書(客戶端)rpc_gss_getcred()svc_req 結構的指標 UNIX 證書、RPCSEC_GSS 證書、cookie
 指定(使用者寫入)回叫函數rpc_gss_set_callback() 回叫函數的指標 TRUE 如果成功的話
 由獨特參數建立主管名稱的 RPCSEC_GSS 結構rpc_gss_get_principal_name() 機制、使用者名稱、機器名稱、領域名稱 RPCSEC_GSS 主管名稱結構
 當 RPCSEC_GSS 常式失敗時提取一個錯誤代碼rpc_gss_get_error()   RPCSEC_GSS 錯誤編號,errno 如適用
 取得所安裝機制的字串rpc_gss_get_mechanisms()    有效的機制清單
 取得有效的 QOP 字串rpc_gss_get_mech_info() 機制 該機制的有效 QOP
 取得 RPCSEC_GSS 所支援的最高、最低的版本編號rpc_gss_get_versions()    最高、最低的版本編號
 查看是否安裝了一個機制rpc_gss_is_installed() 機制 TRUE 如果安裝的話
 將 ASCII 機制轉換為 RPC 物件識別碼rpc_gss_mech_to_oid() 機制(為字串) 機制(為 OID)
 將 ASCII QOP 轉換為整數rpc_gss_qop_to_num() QOP(為字串) QOP(為整數)

建立一個上下文

上下文是以 rpc_gss_seccreate() 呼叫所建立的。此函數以下列所述為其引數﹕

它會傳回一個 AUTH 辯證控點。範例 8-1 會顯示如何使用 rpc_gss_seccreate() 來以 Kerberos V5 安全機制及整合性服務建立一個上下文﹕


範例 8-1 rpc_gss_seccreate()

CLIENT *clnt;                    /* client handle */
char server_host[] = "foo";
char service_name[] = "nfs@eng.acme.com";
char mech[] = "kerberos_v5";

clnt = clnt_create(server_host, SERVER_PROG, SERV_VERS, "netpath");
clnt->clnt_auth = rpc_gss_seccreate(clnt, service_name, mech,
                          rpc_gss_svc_integrity, NULL, NULL, NULL);

. . .

有關 範例 8-1 的幾點注意事項為﹕

如需更詳細的資訊,請參見 rpc_gss_seccreate(3N) 線上援助頁。

變更數值並且損毀一個上下文

一旦設定上下文之後,應用程式可能必須變更被傳送的個別資料單位的 QOP 及服務數值。(例如您需要程式去加密一個密碼但非登入名稱。)rpc_gss_set_defaults() 允許您這麼做﹕


範例 8-2 rpc_gss_set_defaults()

rpc_gss_set_defaults(clnt->clnt_auth, rpc_gss_svc_privacy, qop);

. . .

這__的安全服務是設定為保密性(請參見 "建立一個上下文")。 qop 是一個名為新 QOP 的字串的指標。

上下文會以 auth_destroy() 像平常一樣被損毀。

如需變更服務及 QOP 的詳細資訊,請參見 rpc_gss_set_defaults(3N) 線上援助頁。

主管名稱

需要兩種主管名稱來建立與維護一個安全的上下文﹕

設定伺服器主管名稱

一個伺服器必須在啟動時被告知它將代表的主管名稱。(一個伺服器可以作為一個以上的主管。)rpc_gss_set_svc_name() 設定主管名稱﹕


範例 8-3 rpc_gss_set_svc_name()

char *principal, *mechanism;
 u_int req_time;

 principal = "nfs@eng.acme.com";
 mechanism = "kerberos_v5";
 req_time = 10000;		/* time for which credential should be valid */ 
rpc_gss_set_svc_name(principal, mechanism, req_time, SERV_PROG, SERV_VERS);

(Kerberos 會忽視 req_time 參數。其他的辯證系統可能會使用它。)

如需更詳細的資訊,請參見 rpc_gss_set_svc_name(3N) 線上援助頁。

生成客戶端主管名稱

伺服器必須能夠在一個客戶端的主管名稱之上操作 - 例如將一個客戶端主管名稱與一個存取控制清單做比較,或是為該客戶端查詢一張 UNIX 證書,如果此種證書存在的話。此種主管名稱是以rpc_gss_principal_t結構指標的形式保存的。(請參見 rpcsec_gss(3N) 線上援助頁中有關 rpc_gss_principal_t 的說明。)如果一個伺服器想要比較所收到的一個主管名稱與一個已知實體的名稱,它必須能夠生成該形式的主管名稱。

rpc_gss_get_principal_name() 呼叫作為輸入數種專門代表網路上特定個人的參數,並且將一個主管名稱生成為 rpc_gss_principal_t 結構指標﹕


範例 8-4 rpc_gss_get_principal_name()

rpc_gss_principal_t *principal;

rpc_gss_get_principal_name(principal, mechanism, name, node, domain);
. . .

rpc_gss_get_principal_name() 的引數如下﹕

每一種安全機制都需要不同的辨識參數。例如 Kerberos V5 需要一個使用者名稱,以及選擇性的合格節點和領域名稱(Kerberos 中稱為主機及範疇名稱)。

如需更詳細的資訊,請參見 rpc_gss_get_principal_name(3N) 線上援助頁。

釋放主管名稱

使用 free() 程式庫呼叫來釋放主管名稱。

在伺服器接收證書

伺服器必須能夠提取一個客戶端的證書。範例 8-5 中所示的 rpc_gss_getcred() 函數允許伺服器擷取 UNIX 證書或是 RPCSEC_GSS 證書(或兩者皆是)。它會藉由函數成功之後被設定的兩個引數來達到此目的。其中一個是 rpc_gss_ucred_t 結構的指標,其中包含呼叫者的 UNIX 證書,如果存在的話﹕

typedef struct {
    uid_t   uid;          /* user ID */
    gid_t   gid;          /* group ID */
    short   gidlen;       
    git_t   *gidlist;     /* list of groups */
} rpc_gss_ucred_t;

另一個引數則是 rpc_gss_raw_cred_t 結構的指標,此引數如下所示﹕

typedef struct {
		u_int                  version;               /* RPCSEC_GSS program version */
		char                   *mechanism;
		char                   *qop;
		rpc_gss_principal_t    client_principal;     /* client principal name */
		char                   *svc_principal;        /* server principal name */
		rpc_gss_service_t			service;               /* privacy, integrity enum */
} rpc_gss_rawcred_t;
(請參見 "生成客戶端主管名稱" 中有關 rpc_gss_principal_t 結構與如何建立的說明。)因為 rpc_gss_rawcred_t 同時包含客戶端及伺服器的主管名稱,rpc_gss_getcred() 便可以將它們兩個傳回。

範例 8-5 是一種簡單的伺服端配送程序的範例,其中伺服器取得呼叫者的證書。程序取得呼叫者的 UNIX 證書,然後確認使用者的身份,使用機制 QOP 以及 rpc_gss_rcred_t 引數中找到的服務類型。


範例 8-5 取得證書

static void server_prog(struct svc_req *rqstp, SVCXPRT *xprt)
{
		rpc_gss_ucred_t *ucred;
		rpc_gss_rawcred_t *rcred;

		if (rqst->rq_proq == NULLPROC) {
			svc_sendreply(xprt, xdr_void, NULL);
			return;
		}
		/*
		 * authenticate all other requests */
		 */

		switch (rqstp->rq_cred.oa_flavor) {
		case RPCSEC_GSS:
			/*
			 * get credential information
			 */
			rpc_gss_getcred(rqstp, &rcred, &ucred, NULL);
			/*
			* verify that the user is allowed to access
			* using received security parameters by
			* peeking into my config file
			*/
			if (!authenticate_user(ucred->uid, rcred->mechanism,
				rcred->qop, rcred->service)) {
				svcerr_weakauth(xprt);
				return;
			}
			break; 	/* allow the user in */
		default:
			svcerr_weakauth(xprt);
			return;
		} /* end switch */

		switch (rqstp->rq_proq) {
		case SERV_PROC1:
			. . .
		}

		/* usual request processing; send response ... */

		return;

}

如需更詳細的資訊,請參見 rpc_gss_getcred(3N) 線上援助頁。

Cookie

範例 8-5 中,rpc_gss_getcred()(此處是一個 NULL)的最後一個引數是一個使用者定義的 cookie,伺服器將在建立上下文時指定其傳回數值。您可以採用任何適於應用程式的方法來使用一個四位元組數值的 cookie - RPC 並不會將它解譯。例如 cookie 可以是代表上下文指標結構的一個指標或索引;伺服器不會為每個要求計算此數值,反而會依照建立上下文的時間來計算它(因此而節省處理要求的時間)。

回叫

另一個可以使用 cookie 的地方是回叫。一個伺服器可以指定(使用者定義的)回叫,因此它會利用 rpc_gss_set_callback() 函數而得知上下文何時第一次被使用。回叫會在在為指定的程式及版本建立上下文之後,資料交換第一次使用上下文時被調用。

使用者定義的回叫常式有下列各種形式﹕

第二及第三個引數﹕deleggss_context 是 GSS-API 的資料類型,而且目前尚未被公開,因此回叫函數可以忽視它們。(簡而言之,deleg 是任何被指派的同層的身份,而 gss_context 則是 GSS-API 上下文的指標,如果程式想要在上下文之上執行 GSS-API 操作 - 也就是要測試接受條件的話。)前面我們已經談過 cookie 引數。

lock 引數是 rpc_gss_lock_t 結構的指標﹕

typedef struct {
		bool_t              locked;
		rpc_gss_rawcred_t   *raw_cred;
} rpc_gss_lock_t;
此參數會啟用一個伺服器以強迫實行一個作業階段的特定 QOP 及服務。範例 8-5 中所述的rpc_gss_rawcred_t 結構中包括 QOP 及服務。(一個伺服器不應該變更服務及 QOP 的數值)。當使用者定義的回叫被調用時,locked 欄位被設定為 FALSE。如果伺服器將 locked 設定為 TRUE,那麼只有 QOP 及服務數值符合rpc_gss_rawcred_t 結構中的 QOP 及服務數值符合的要求會被接受。

如需更詳細的資訊,請參見 rpc_gss_set_callback(3N) 線上援助頁。

最大的資料大小

rpc_gss_max_data_length()rpc_gss_svc_max_data_length() 兩個函數可以決定在以安全措施“透過線路來傳送一筆資料之前,資料的大小應該多大。”因為如加密的安全傳送通常會變更一筆傳送的資料大小(通常會將它加大)。要確定資料不會被加大而超出適用的大小,這兩個函數 - 前者為客戶端版本,後者為伺服端 - 會傳回一個特定傳輸的最大事先傳送大小。

如需更詳細的資訊,請參見 rpc_gss_max_data_length(3N)rpc_gss_svc_max_data_length(3N) 線上援助頁。

其他函數

有數種函數可以用來取得有關安裝的安全系統資訊﹕

使用這些函數可以提供程式設計師足夠的回旋餘地以避免將安全參數硬性編碼入應用程式中。(請參見 表 8-1rpcsec_gss(3N) 線上援助頁中所有 RPCSEC_GSS 函數的清單。)

相關的檔案

RPCSEC_GSS 會利用特定的檔案來貯存資訊。

gsscred

當伺服器擷取與一項要求有關的客戶端證書時,它會取得客戶端的主管名稱(rpc_gss_principal_t 結構指標的形式),或是該客戶端的本機 UNIX 證書 (UID)。如 NFS 的服務需要一個本機 UNIX 證書以供存取檢查之用,但是其他服務可能就不需要。例如它們可以將主管名稱貯存為 rpc_gss_principal_t 結構,直接位元其本身的存取控制清單中。


註解 -

客戶端的網路證書(其主管名稱)和任何本機 UNIX 證書之間的通信不是自動的 - 它必須由本機安全管理員明確設定。


gsscred 檔案同時包含客戶端的 UNIX 以及網路(例如 Kerberos V5)證書。(後者是十六進制的 ASCII 式 rpc_gss_principal_t 結構的。)它可以透過 XFN 來存取;因此此表可以在檔案、NIS、或 NIS+、或是任何 XFN 所支援的未來名稱服務上實行。在 XFN 階層中,此表代表的是this_org_unit/服務/gsscredgsscred 表是利用 gsscred 公用程式來加以維護,以允許管理員新增與刪除使用者及機制。

/etc/gss/qop/etc/gss/mech

為了方便起見,RPCSEC_GSS 使用字串的字面意義來代表機制及保護品質 (QOP) 參數。不過下層的機制本身需要所代表的機制為物件識別碼以及 QOP 為 32 位元的整數。此外還必須指定為每一個機制實行服務的共享程式庫。

/etc/gss/mech 檔案可以貯存下列有關一個系統上所有安裝的機制資訊﹕ASCII 格式的機制名稱;機制的 OID;此機制提供的實行服務的共享程式庫;以及選擇性的,實行服務的 kernel(核心)模組。其範例如下﹕


kerberos_v5   1.2.840.113554.1.2.2    gl/mech_krb5.so gl_kmech_krb5

/etc/gss/qop 檔案會為安裝的所有機制貯存每個機制所支援的所有 QOP,為一個 ASCII 字串為其相應的 32 位元整數。

/etc/gss/mech/etc/gss/qop 都會在第一次將安全機制安裝在一個特定的系統之上時建立。

因為許多 kernel 內 RPC 常式都使用非字串數值來代表機制及 QOP,應用程式在需要利用那些 kernel 內 常式時,便可以使用 rpc_gss_mech_to_oid()rpc_gss_qop_to_num() 函數來取得這些參數的同等非字串。