?? ssl_client.c
字號:
/* * OpenSSL-based CAS ticket validator by Shawn Bayern, based on * OpenSSL demonstration code. */#include <stdio.h>#include <memory.h>#include <errno.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <netdb.h>#include <openssl/crypto.h>#include <openssl/x509.h>#include <openssl/pem.h>#include <openssl/ssl.h>#include <openssl/err.h>#include "cas.h"#define END(x) { ret = (x); goto end; }#define FAIL END(0)#define FAIL_BAD_CERT END(BAD_CERT)#define SUCCEED END(1)/* * TODO: This really ought to be configurable at runtime. At least you * can declare multiple CA certificates easily (at compile time) through * this array. */static char *trusted_ca[] = { "/usr/local/etc/verisignserverca.pem", NULL};int CAS_validate(char *ticket, char *service, char *outbuf, int outbuflen);static X509 *get_cert_from_file(char *filename);static int valid_cert(X509 *cert, char *hostname);/** Returns status of certification: 0 for invalid, 1 for valid. */static int valid_cert(X509 *cert, char *hostname){ int i; char buf[4096]; X509_STORE *store = X509_STORE_new(); X509_STORE_CTX *ctx = X509_STORE_CTX_new(); for (i = 0; trusted_ca[i] != NULL; i++) { X509 *cacert = get_cert_from_file(trusted_ca[i]); if (cacert) X509_STORE_add_cert(store, cacert); } X509_STORE_CTX_init(ctx, store, cert, sk_X509_new_null()); if (X509_verify_cert(ctx) == 0) return 0; X509_NAME_get_text_by_NID(X509_get_subject_name(cert), NID_commonName, buf, sizeof(buf) - 1); // anal-retentive: make sure the hostname isn't as long as the // buffer, since we don't want to match only because of truncation if (strlen(hostname) >= sizeof(buf) - 1) return 0; return (!strcmp(buf, hostname));}/** Returns status of ticket by filling 'buf' with a NetID if the ticket * is valid and buf is large enough and returning 1. If not, 0 is * returned. */int CAS_validate(char *ticket, char *service, char *outbuf, int outbuflen){ int err, b, ret, total; int s = 0; struct sockaddr_in sa; struct hostent h, *hp2; SSL_CTX *ctx = NULL; SSL *ssl = NULL; X509 *s_cert = NULL; char buf[4096]; SSL_METHOD *method; char *full_request, *str, *tmp; SSLeay_add_ssl_algorithms(); method = SSLv23_client_method(); SSL_load_error_strings(); ctx = SSL_CTX_new(method); if (!ctx) FAIL; if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1) FAIL; memset(&sa, 0, sizeof(sa)); sa.sin_family = AF_INET; hp2 = gethostbyname(CAS_HOST); memcpy(&h, hp2, sizeof(h));// gethostbyname_r(CAS_HOST, &h, buf, sizeof(buf), &hp2, &b); memcpy(&(sa.sin_addr.s_addr), h.h_addr_list[0], sizeof(long)); sa.sin_port = htons(CAS_PORT); if (connect(s, (struct sockaddr*) &sa, sizeof(sa)) == -1) FAIL; if (!(ssl = SSL_new(ctx))) FAIL; SSL_set_fd(ssl, s); if (!SSL_connect(ssl)) FAIL; if (!(s_cert = SSL_get_peer_certificate(ssl))) FAIL_BAD_CERT; if (!valid_cert(s_cert, CAS_HOST)) FAIL_BAD_CERT; X509_free(s_cert); full_request = malloc(strlen(CAS_METHOD) + strlen(" ") + strlen(CAS_VALIDATE) + strlen("?ticket=") + strlen(ticket) + + strlen("&service=") + strlen(service) + strlen(" ") + strlen(CAS_PROT) + strlen("\n\n") + 1); sprintf(full_request, "%s %s?ticket=%s&service=%s %s\n\n", CAS_METHOD, CAS_VALIDATE, ticket, service, CAS_PROT); if (!SSL_write(ssl, full_request, strlen(full_request))) FAIL; total = 0; do { b = SSL_read(ssl, buf + total, (sizeof(buf) - 1) - total); total += b; } while (b > 0); buf[total] = '\0'; if (b != 0 || total >= sizeof(buf) - 1) FAIL; // unexpected read error or response too large /* * The following segment of code is spelled out in excruciating detail * since it's worth the extra care. */ str = strstr(buf, "\r\n\r\n"); // find the end of the header if (!str) FAIL; // no header str += 4; // safe because we just found "\r\n\r\n" if (strncmp(str, "yes", 3)) FAIL; // no affirmative response str = strchr(str, '\n'); // find the end of the current line if (!str) { str = strchr(str, '\r'); // possibly ended in CR (ok by RFC-2616) if (!str) FAIL; // unexpectedly short body } str++; // safe because we just found "\n" or "\r" // now, we've got the NetID and a bunch of crap after it. Find the next // '[\r]\n' and end the string there { char *str2 = strchr(str, '\r'); if (!str2) { str2 = strchr(str, '\n'); if (!str2) FAIL; // unexpectedly short body } *str2 = '\0'; // remove [\r]\n } /* * without enough space, fail entirely, since a partial NetID could * be dangerous */ if (outbuflen < strlen(str) + 1) FAIL; strcpy(outbuf, str); SUCCEED; /* cleanup and return */end: if (ssl) SSL_shutdown(ssl); if (s > 0) close(s); if (ssl) SSL_free(ssl); if (ctx) SSL_CTX_free(ctx); return ret;}static X509 *get_cert_from_file(char *filename) { FILE *f = fopen(filename, "r"); if (f) { X509 *c = PEM_read_X509(f, NULL, NULL, NULL); fclose(f); return c; } else { return NULL; }}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -