다음을 통해 공유


GSSAPI와 SSPI/Kerberos 상호 운용성

GSSAPI와의 상호 운용성이 요구 사항인 경우 Kerberos SSP(보안 지원 공급자)를 사용하는 경우 주의해야 합니다. 다음 코드 규칙은 GSSAPI 기반 애플리케이션과의 상호 운용성을 허용합니다.

샘플\Security\SSPI\GSS 아래의 SDK(Platform Software Development Kit)에서 샘플 코드를 찾을 수 있습니다. 또한 동등한 UNIX 샘플은 MIT 및 Heimdal Kerberos 배포, GSS 클라이언트 및 서버에 배포됩니다.

Windows 호환 이름

GSSAPI 함수는 RFC에 지정된 대로 gss_nt_service_name 이름 형식을 사용합니다. 예를 들어 sample@host.dom.com GSSAPI 기반 애플리케이션에서 사용할 수 있는 이름입니다. Windows 운영 체제는 gss_nt_service_name 형식을 인식하지 못하며 전체 서비스 주체 이름(예: sample/host.dom.com@REALM)을 사용해야 합니다.

인증

인증은 일반적으로 클라이언트와 서버 간에 연결이 처음 설정될 때 처리됩니다. 이 샘플에서 클라이언트는 SSPI(보안 지원 공급자 인터페이스)를 사용하고 서버는 GSSAPI를 사용합니다.

SSPI 클라이언트에서 인증을 설정하려면

  1. AcquireCredentialsHandle을 사용하여 아웃바운드 자격 증명을 가져옵니다.
  2. gss_import_name()를 사용하여 서비스 이름을 만들고 gss_acquire_cred 사용하여 인바운드 자격 증명을 가져옵니다.
  3. InitializeSecurityContext(Kerberos)를 사용하여 서버에 보낼 인증 토큰을 가져옵니다.
  4. 서버에 토큰을 보냅니다.

GSSAPI 서버에서 인증을 설정하려면

  1. 클라이언트에서 메시지를 구문 분석하여 보안 토큰을 추출합니다. gss_accept_sec_context 함수를 사용하여 토큰을 인수로 전달합니다.

  2. 서버에서 메시지를 구문 분석하여 보안 토큰을 추출합니다. 이 보안 토큰을 InitializeSecurityContext(Kerberos)에 전달합니다.

  3. 클라이언트에 응답 토큰을 보냅니다.

    gss_accept_sec_context 함수는 클라이언트로 다시 보낼 수 있는 토큰을 반환할 수 있습니다.

  4. 계속해야 하는 경우 응답 토큰을 서버에 보냅니다. 그렇지 않으면 인증 설정이 완료됩니다.

  5. 계속해야 하는 경우 클라이언트에서 다음 토큰을 기다립니다. 그렇지 않으면 인증 설정이 완료됩니다.

메시지 무결성 및 개인 정보

대부분의 GSSAPI 기반 애플리케이션은 GSS_Wrap 함수를 사용하여 메시지를 보내기 전에 서명합니다. 반대로 GSS_Unwrap 함수는 서명을 확인합니다. GSS_Wrap API 버전 2.0에서 사용할 수 있으며 이제 프로토콜에 보안을 추가하기 위해 GSSAPI를 사용하는 방법을 설명하는 인터넷 표준에서 널리 사용되고 지정됩니다. 이전에는 GSS SignMessage 및 SealMessage 함수가 메시지 무결성 개인 정보 보호에 사용되었습니다. GSS_Wrap 및 GSS_Unwrap "conf_flag" 인수의 값으로 제어되는 개인 정보를 사용하여 무결성과 개인 정보 보호 모두에 사용됩니다.

gss_get_mic 및 gss_verify_mic 함수를 사용하도록 GSSAPI 기반 프로토콜을 지정한 경우 올바른 SSPI 함수는 MakeSignatureVerifySignature입니다. makeSignature 및 VerifySignature는 conf_flag 0으로 설정되거나 GSS_Unwrap 사용할 때 GSS_Wrap 상호 운용되지 않습니다. 서명 전용 및 gss_verify_mic 대해 설정된 EncryptMessage(Kerberos)를 혼합하는 경우도 마찬가지입니다.

참고 항목

GSS_Wrap 및 GSS_Unwrap 호출되는 경우 MakeSignature 또는 VerifySignature 함수를 사용하지 마세요.

 

GSS_Wrap 해당하는 SSPI는 무결성과 개인 정보 모두에 대한 EncryptMessage(Kerberos)입니다.

다음 예제에서는 EncryptMessage(Kerberos)를 사용하여 GSS_Unwrap 확인할 데이터에 서명하는 방법을 보여 줍니다.

SSPI 클라이언트에서:

// Need three descriptors, two for the SSP and
// one to hold the application data. 
in_buf_desc.cBuffers = 3;
in_buf_desc.pBuffers = wrap_bufs;
in_buf_desc.ulVersion = SECBUFFER_VERSION;
wrap_bufs[0].cbBuffer = sizes.cbSecurityTrailer;
wrap_bufs[0].BufferType = SECBUFFER_TOKEN;
wrap_bufs[0].pvBuffer = malloc(sizes.cbSecurityTrailer);

// This buffer holds the application data.
wrap_bufs[1].BufferType = SECBUFFER_DATA;
wrap_bufs[1].cbBuffer = in_buf.cbBuffer;
wrap_bufs[1].pvBuffer = malloc(wrap_bufs[1].cbBuffer);
memcpy(wrap_bufs[1].pvBuffer, in_buf.pvBuffer, in_buf.cbBuffer);
wrap_bufs[2].BufferType = SECBUFFER_PADDING;
wrap_bufs[2].cbBuffer = sizes.cbBlockSize;
wrap_bufs[2].pvBuffer = malloc(wrap_bufs[2].cbBuffer);
maj_stat = EncryptMessage(&context,
SignOnly ? KERB_WRAP_NO_ENCRYPT : 0,
&in_buf_desc, 0);

// Send a message to the server.

GSSAPI 서버에서:

// Received message is in recv_buf. 
maj_stat = gss_unwrap(&min_stat, context, &recv_buf, &msg_buf,
    &conf_state, (gss_qop_t *) NULL);
(void) gss_release_buffer(&min_stat, &recv_buf);

// Original message is in msg_buf.

GSS_Unwrap 해당하는 SSPI는 DecryptMessage(Kerberos)입니다. 다음은 DecryptMessage(Kerberos)를 사용하여 GSS_Wrap 암호화된 데이터의 암호를 해독하는 방법을 보여 주는 예제입니다.

GSSAPI 서버에서:

// Seal the message.
send_buf.value = msg;
send_buf.length = msglen;

// If encrypt_flag = 1, privacy; encrypt_flag = 0, integrity.
maj_stat = gss_wrap(&min_stat, context, encrypt_flag,
    GSS_C_QOP_DEFAULT, &send_buf, &state, &msg_buf); 

// The message to send is in msg_buf.

SSPI 클라이언트에서:

wrap_buf_desc.cBuffers = 2;
wrap_buf_desc.pBuffers = wrap_bufs;
wrap_buf_desc.ulVersion = SECBUFFER_VERSION; 

// This buffer is for SSPI.
wrap_bufs[0].BufferType = SECBUFFER_STREAM;
wrap_bufs[0].pvBuffer = xmit_buf.pvBuffer;
wrap_bufs[0].cbBuffer = xmit_buf.cbBuffer;

// This buffer holds the application data.
wrap_bufs[1].BufferType = SECBUFFER_DATA;
wrap_bufs[1].cbBuffer = 0;
wrap_bufs[1].pvBuffer = NULL;
maj_stat = DecryptMessage(
&context,
&wrap_buf_desc,
0, // no sequence number
&qop
);

// This is where the data is.
msg_buf = wrap_bufs[1];

// Check QOP of received message.
// If QOP is KERB_WRAP_NO_ENCRYPT, the message is signed only; 
// otherwise, it is encrypted.