| 前へ << 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 までお願いします。