前へ << SSL/TLS でアクセスしてみよう (1) | RSA で暗号化してみよう (1) >> 次へ |
なりすましは、サーバ認証を行うことで防ぐことができます。
公開鍵と秘密鍵は誰でも作れます。 誰でも証明局になることができます (公開鍵と秘密鍵を作った本人でも)。 よって、サーバ証明書も誰でも発行できます。
(以下未稿)
% ./https-client-2 rsasecurity.com / 使用する暗号化方式は RC4-MD5 です。 使用するプロトコルは TLSv1/SSLv3 です。 サーバ証明書: Subject: CN=www.rsasecurity.com,OU=Information Services,O=RSA Security Inc.,L=Bedford,ST=Massachusetts,C=US Issuer: C=US,ST=Massachusetts,L=Bedford,CN=RSA Corporate Server CA,OU=KCA Services,O=RSA Security Inc. 有効期限開始年月日: Sep 16 14:55:55 2003 GMT 有効期限終了年月日: Sep 16 14:55:55 2004 GMT 認証に成功しました。エラーはありません。 サーバからのレスポンス (略)https://www2.ggn.net/cgi-bin/ssl にアクセスした場合。
% ./https-client-2 使用する暗号化方式は EDH-RSA-DES-CBC3-SHA です。 使用するプロトコルは TLSv1/SSLv3 です。 サーバ証明書: Subject: CN=www.ggn.com,O=Gillette Global Network,L=New York,ST=New York,C=US Issuer: O=Gillette Global Network,L=New York,ST=New York,C=US 有効期限開始年月日: Feb 18 00:49:07 2000 GMT 有効期限終了年月日: Feb 17 00:49:07 2001 GMT 認証時にエラー発生。続行します。 SSL_get_verify_result の戻り値 = 20 unable to get local issuer certificate サーバからのレスポンス HTTP/1.1 200 OK Date: Sat, 14 Jun 2003 12:38:52 GMT Server: Apache/1.3.26 (Unix) GGN-MM/1.3.1 mod_ssl/2.8.10 OpenSSL/0.9.6d Connection: close Content-Type: text/html (略)
1: /* 2: * $Id: https-client-2.c,v 1.6 2005/02/19 16:01:53 68user Exp $ 3: * 4: * HTTPS (SSL/TLS) クライアント (2) 5: * サーバ認証・証明書情報の表示 6: * 7: * written by 68user http://X68000.q-e-d.net/~68user/ 8: */ 9: 10: #include <stdio.h> 11: #include <string.h> 12: #include <sys/types.h> 13: #include <netdb.h> 14: #include <sys/socket.h> 15: #include <netinet/in.h> 16: #include <sys/types.h> 17: #include <sys/uio.h> 18: #include <unistd.h> 19: 20: #include <openssl/crypto.h> 21: #include <openssl/x509.h> 22: #include <openssl/pem.h> 23: #include <openssl/ssl.h> 24: #include <openssl/err.h> 25: 26: #define BUF_LEN 256 27: 28: /* root CA の証明書 */ 29: #define ROOT_CA "ca-bundle.crt" 30: 31: void verify_ssl(SSL *ssl); 32: 33: int 34: main(argc, argv) 35: int argc; 36: char *argv[]; 37: { 38: int err; 39: int s; 40: struct hostent *servhost; 41: struct sockaddr_in server; 42: struct servent *service; 43: 44: SSL *ssl; 45: SSL_CTX *ctx; 46: SSL_METHOD *(*ssl_method)() = SSLv23_client_method; 47: X509 *server_cert; 48: 49: char request[BUF_LEN]; 50: 51: char *host = "www2.ggn.net"; 52: char *path = "/cgi-bin/ssl"; 53: 54: if ( argc > 1 ){ 55: if ( strcmp(argv[1], "-sslv2") == 0 ){ 56: ssl_method = SSLv2_client_method; 57: argc--; argv++; 58: } else if ( strcmp(argv[1], "-sslv3") == 0 ){ 59: ssl_method = SSLv3_client_method; 60: argc--; argv++; 61: } else if ( strcmp(argv[1], "-tlsv1") == 0 ){ 62: ssl_method = TLSv1_client_method; 63: argc--; argv++; 64: } else if ( strcmp(argv[1], "-sslv23") == 0 ){ 65: ssl_method = SSLv23_client_method; 66: argc--; argv++; 67: } 68: } 69: if ( argc == 3 ){ 70: host = argv[1]; 71: path = argv[2]; 72: } 73: 74: servhost = gethostbyname(host); 75: if ( servhost == NULL ){ 76: fprintf(stderr, "[%s] から IP アドレスへの変換に失敗しました。\n", host); 77: return 0; 78: } 79: 80: bzero((char *)&server, sizeof(server)); 81: 82: server.sin_family = AF_INET; 83: 84: bcopy(servhost->h_addr, (char *)&server.sin_addr, servhost->h_length); 85: 86: /* ポート番号取得 */ 87: service = getservbyname("https", "tcp"); 88: if ( service != NULL ){ 89: server.sin_port = service->s_port; 90: } else { 91: /* 取得できなかったら、ポート番号を 443 に決め打ち */ 92: server.sin_port = htons(443); 93: } 94: 95: s = socket(AF_INET, SOCK_STREAM, 0); 96: if ( s < 0 ){ 97: fprintf(stderr, "ソケットの生成に失敗しました。\n"); 98: return 1; 99: } 100: 101: if ( connect(s, (struct sockaddr*) &server, sizeof(server)) == -1 ){ 102: fprintf(stderr, "connect に失敗しました。\n"); 103: return 1; 104: } 105: 106: /* ここからが SSL */ 107: 108: SSL_library_init(); 109: SSL_load_error_strings(); 110: ctx = SSL_CTX_new(ssl_method()); 111: 112: /* rootCA を登録 */ 113: if ( ! SSL_CTX_load_verify_locations(ctx, ROOT_CA, NULL) ){ 114: printf("rootCA [%s] の読み込みに失敗しましたが続行します。\n", ROOT_CA); 115: } 116: 117: ssl = SSL_new(ctx); 118: SSL_set_fd(ssl, s); 119: err = SSL_connect(ssl); 120: 121: /* どの暗号化方式を使用するかを表示 (DES-CBC3-MD5 など) */ 122: { 123: const char *cipher; 124: cipher = SSL_get_cipher(ssl); 125: printf("使用する暗号化方式は %s です。\n", cipher); 126: } 127: 128: /* どの SSL プロトコルを使用するかを表示 (SSLv2, SSLv3/TLSv1 など) */ 129: { 130: char *version; 131: version = SSL_get_cipher_version(ssl); 132: printf("使用するプロトコルは %s です。\n", version); 133: } 134: 135: server_cert = SSL_get_peer_certificate(ssl); 136: printf("サーバ証明書:\n"); 137: 138: { 139: BIO *STDout = BIO_new_fp(stdout, BIO_NOCLOSE); 140: 141: BIO_printf(STDout, " Subject: "); 142: X509_NAME_print_ex(STDout, X509_get_subject_name(server_cert), 0, XN_FLAG_RFC2253); 143: BIO_printf(STDout, "\n"); 144: 145: BIO_printf(STDout, " Issuer: "); 146: X509_NAME_print_ex(STDout, X509_get_issuer_name(server_cert), 0, XN_FLAG_RFC2253); 147: BIO_printf(STDout, "\n"); 148: 149: ASN1_TIME *notBefore = X509_get_notBefore(server_cert); 150: ASN1_TIME *notAfter = X509_get_notAfter(server_cert); 151: 152: BIO_printf(STDout, " 有効期限開始年月日: "); 153: ASN1_TIME_print(STDout, notBefore); 154: BIO_printf(STDout, "\n"); 155: BIO_printf(STDout, " 有効期限終了年月日: "); 156: ASN1_TIME_print(STDout, notAfter); 157: BIO_printf(STDout, "\n"); 158: BIO_free(STDout); 159: } 160: 161: verify_ssl(ssl); 162: 163: X509_free(server_cert); 164: 165: /* リクエストを送る */ 166: 167: sprintf(request, "GET %s HTTP/1.0\r\nHost: %s\r\n\r\n", 168: path, host); 169: 170: err = SSL_write(ssl, request, strlen(request)); 171: 172: /* web サーバからレスポンスを受け取る */ 173: 174: printf("サーバからのレスポンス\n"); 175: 176: while (1){ 177: char buf[BUF_LEN]; 178: int read_size; 179: read_size = SSL_read(ssl, buf, sizeof(buf)-1); 180: buf[read_size] = '\0'; 181: 182: if ( read_size > 0 ){ 183: write(1, buf, read_size); 184: } else { 185: break; 186: } 187: } 188: 189: SSL_shutdown(ssl); 190: 191: close(s); 192: SSL_free(ssl); 193: SSL_CTX_free(ctx); 194: 195: return 0; 196: } 197: 198: 199: void 200: verify_ssl(SSL *ssl){ 201: long verify_result; 202: 203: struct sslerror_t { 204: long result_code; 205: char *ssl_error; 206: char *ssl_errordetail; 207: }; 208: 209: struct sslerror_t error_table[]={ 210: {X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT, 211: "unable to get issuer certificate. ", 212: "the issuer certificate could not be found: this occurs if the" 213: "issuer certificate of an untrusted certificate cannot be found." 214: }, 215: {X509_V_ERR_UNABLE_TO_GET_CRL, 216: "unable to get certificate CRL. ", 217: "the CRL of a certificate could not be found. Unused." 218: }, 219: {X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE, 220: "unable to decrypt certificate's signature", 221: "the certificate signature could not be decrypted. This means that" 222: "the actual signature value could not be determined rather than it" 223: "not matching the expected value, this is only meaningful for RSA keys" 224: }, 225: {X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE, 226: "unable to decrypt CRL's signature", 227: "the CRL signature could not be decrypted: this means that the" 228: "actual signature value could not be determined rather than it not" 229: "matching the expected value. Unused." 230: }, 231: {X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY, 232: "unable to decode issuer public key", 233: "the public key in the certificate SubjectPublicKeyInfo could not be read" 234: }, 235: {X509_V_ERR_CERT_SIGNATURE_FAILURE, 236: "certificate signature failure", 237: "the signature of the certificate is invalid" 238: }, 239: {X509_V_ERR_CRL_SIGNATURE_FAILURE, 240: "CRL signature failure", 241: "the signature of the certificate is invalid. Unused" 242: }, 243: {X509_V_ERR_CERT_NOT_YET_VALID, 244: "証明書の有効期限が未来日付", 245: "証明書が有効になる開始日付にまだ達していません。" 246: "時刻設定がおかしくない?" 247: }, 248: {X509_V_ERR_CERT_HAS_EXPIRED, 249: "証明書の有効期限切れ", 250: "証明書が古いす", 251: }, 252: {X509_V_ERR_CRL_NOT_YET_VALID, 253: "CRL is not yet valid", 254: "the CRL is not yet valid. Unused." 255: }, 256: {X509_V_ERR_CRL_HAS_EXPIRED, 257: "CRL has expired", 258: "the CRL has expired. Unused." 259: }, 260: {X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD, 261: "format error in certificate's notBefore field", 262: "the certificate notBefore field contains an invalid time" 263: }, 264: {X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD, 265: "format error in certificate's notAfter field", 266: "the certificate notAfter field contains an invalid time." 267: }, 268: {X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD, 269: "format error in CRL's lastUpdate field", 270: "the CRL lastUpdate field contains an invalid time. Unused." 271: }, 272: {X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD, 273: "format error in CRL's nextUpdate field", 274: "the CRL nextUpdate field contains an invalid time. Unused.", 275: }, 276: {X509_V_ERR_OUT_OF_MEM, 277: "メモリ不足", 278: "メモリを確保できませんでした。このエラーは発生するべきではありません。" 279: }, 280: {X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT, 281: "self signed certificate", 282: "the passed certificate is self signed and the same certificate" 283: "cannot be found in the list of trusted certificates." 284: }, 285: {X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN, 286: "self signed certificate in certificate chain", 287: "the certificate chain could be built up using the untrusted" 288: "certificates but the root could not be found locally." 289: }, 290: {X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY, 291: "unable to get local issuer certificate", 292: "the issuer certificate of a locally looked up certificate could not" 293: "be found. This normally means the list of trusted certificates is" 294: "not complete." 295: }, 296: {X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE, 297: "unable to verify the first certificate", 298: "no signatures could be verified because the chain contains only one" 299: "certificate and it is not self signed." 300: }, 301: {X509_V_ERR_CERT_CHAIN_TOO_LONG, 302: "certificate chain too long", 303: "the certificate chain length is greater than the supplied maximum" 304: "depth. Unused." 305: }, 306: {X509_V_ERR_CERT_REVOKED, 307: "certificate revoked", 308: "the certificate has been revoked. Unused." 309: }, 310: {X509_V_ERR_INVALID_CA, 311: "invalid CA certificate", 312: "a CA certificate is invalid. Either it is not a CA or its" 313: "extensions are not consistent with the supplied purpose." 314: }, 315: {X509_V_ERR_PATH_LENGTH_EXCEEDED, 316: "path length constraint exceeded", 317: "the basicConstraints pathlength parameter has been exceeded." 318: }, 319: {X509_V_ERR_INVALID_PURPOSE, 320: "unsupported certificate purpose", 321: "the supplied certificate cannot be used for the specified purpose." 322: }, 323: {X509_V_ERR_CERT_UNTRUSTED, 324: "certificate not trusted", 325: "the root CA is not marked as trusted for the specified purpose." 326: }, 327: {X509_V_ERR_CERT_REJECTED, 328: "証明書が拒絶された", 329: "the root CA is marked to reject the specified purpose.", 330: }, 331: {X509_V_ERR_SUBJECT_ISSUER_MISMATCH, 332: "subject issuer mismatch", 333: "the current candidate issuer certificate was rejected because its" 334: "subject name did not match the issuer name of the current" 335: "certificate. Only displayed when the -issuer_checks option is set." 336: }, 337: {X509_V_ERR_AKID_SKID_MISMATCH, 338: "authority and subject key identifier mismatch", 339: "the current candidate issuer certificate was rejected because its" 340: "subject key identifier was present and did not match the authority" 341: "key identifier current certificate. Only displayed when the" 342: "-issuer_checks option is set." 343: }, 344: {X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH, 345: "authority and issuer serial number mismatch", 346: "the current candidate issuer certificate was rejected because its" 347: "issuer name and serial number was present and did not match the" 348: "authority key identifier of the current certificate. Only displayed" 349: "when the -issuer_checks option is set." 350: }, 351: {X509_V_ERR_KEYUSAGE_NO_CERTSIGN, 352: "key usage does not include certificate signing", 353: "the current candidate issuer certificate was rejected because its" 354: "keyUsage extension does not permit certificate signing." 355: }, 356: {X509_V_ERR_APPLICATION_VERIFICATION, 357: "application verification failure", 358: "an application specific error. Unused." 359: } 360: }; 361: 362: verify_result = SSL_get_verify_result(ssl); 363: 364: if ( verify_result == X509_V_OK ){ 365: printf("認証に成功しました。エラーはありません。\n"); 366: } else { 367: int i; 368: 369: printf("認証時にエラー発生。続行します。\n"); 370: for ( i=0 ; i<sizeof(error_table)/sizeof(error_table[0]) ; i++ ){ 371: if ( error_table[i].result_code == verify_result ){ 372: printf(" SSL_get_verify_result の戻り値 = %d\n", (int)verify_result); 373: printf(" %s\n", error_table[i].ssl_error); 374: break; 375: } 376: } 377: } 378: }rootCA の証明書。mod_ssl の配布物に含まれているものをそのままいただきました。 https-client-2 を実行する際、カレントディレクトリに置いてください。 ca-bundle.crt
前へ << SSL/TLS でアクセスしてみよう (1) | RSA で暗号化してみよう (1) >> 次へ |
ご意見・ご指摘は Twitter: @68user までお願いします。