Advertisement
Guest User

Untitled

a guest
Apr 9th, 2014
668
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 21.35 KB | None | 0 0
  1. Text of https://www.peereboom.us/assl/assl/html/openssl.html
  2.  
  3. SSL certificate seems to be invalid, so i braved it for the rest of us.
  4.  
  5. ---
  6.  
  7. I know it sounds harsh but lets investigate the facts.
  8. First lets get out of the way who is complaining. Hi, I am Marco Peereboom and I write open source code for fun. I have been involved in several projects and the google will tell you which ones. I am by no stretch of the imagination a great programmer but I have been around and I have written a couple of things.
  9.  
  10. Recently I got involved in writing some code that requires secure communications and I figured that there was no better way to get cranking than to use a well known and widely used library. Essentially my problem boils down to this:
  11.  
  12. Write an application that provides CA (Certificate Authority) services.
  13. Store all certificates in an LDAP tree.
  14. The debate is not about the merit of this idea but this is where the journey started. It sounded simple enough so off to the web looking for documentation and code snippets, this is obviously going to be a walk in the park since all these problems have been solved before.
  15.  
  16. After messing around with this code for about a month I decided to write this up for the tubes in the hope that I can save some souls. I have come to the conclusion that OpenSSL is equivalent to monkeys throwing feces at the wall. It is, bar none, the worst library I have ever worked with. I can not believe that the internet is running on such a ridiculous complex and gratuitously stupid piece of code. Since circa 1998 the whole world has been trusting their secure communications to this impenetrable morass that calls itself the "OpenSSL" project. I bet that the doctors that work on that shitshow can not prescribe anything useful either!
  17.  
  18. Day 1:
  19.  
  20. Hmmm can't find a whole bunch of code at all. What I do find doesn't help me with my CA problem at all. Everything I do find is basically a whole bunch of HOWTOS written by people who don't seem to grasp the underlying problems. They mean well but really hurt the community as a whole by providing recipes for disaster. Alright no problem off to Barnes & Nobles and lets see what we can find.
  21.  
  22. Crap! Nothing really. I found 2 books and they were mostly about using the command line tool. One had some code examples but nothing advanced at all. Apparently people only seem to care about using openssl "the tool".
  23.  
  24. I had peeked at the code and it gave me vertigo so I stepped away from it. Anyway at this point I was starting to suspect that this might not be as easy as I had hopped. Time to go home anyway and drink a cold one.
  25.  
  26. Day 2:
  27.  
  28. Alright screw it! I'll look at the damn code; I mean all books and examples on the web use it. At least it'll point me to what functions I need to call and I'll be able to find those in the fine documentation. First I obviously need to figure out how to use openssl "the tool".
  29.  
  30. 8 hours later...
  31.  
  32. Phew I got something that works after reading endless HOWTOS, specs and postings on the tubes. The documentation was, how does one say that? Really really bad! Let me share with you my labor of love. I created 3 scripts to illustrate my problem of having a CA that signs client and server certificates.
  33.  
  34. create_ca, this script creates the CA
  35. create_server, this script creates a server certificate and keys
  36. create_client, this script creates a client certificate and keys
  37. create_ca
  38. #/bin/sh
  39. mkdir -p ca/private
  40. chmod 700 ca/private
  41. openssl req -x509 -days 3650 -newkey rsa:1024 -keyout ca/private/ca.key -out ca/ca.crt
  42. create_server
  43. #/bin/sh
  44. mkdir -p server/private
  45. chmod 700 server/private
  46. openssl genrsa -out server/private/server.key 1024
  47. openssl req -new -key server/private/server.key -out server/server.csr
  48. create_client
  49. #/bin/sh
  50. mkdir -p client/private
  51. chmod 700 client/private
  52. openssl genrsa -out client/private/client.key 1024
  53. openssl req -new -key client/private/client.key -out client/client.csr
  54. enough for a day. Time to go home.
  55. Day 3: Alright, that openssl "the tool" stuff out of the way lets dig into that code. Hmmm, where is main? How does it call the individual modules? Random camel capitalization mixed with underscores wow! Ugh MAIN macro, great. *WASH_Eyes_outWith_soap*
  56.  
  57. Ok we are going to need some serious tags to be able to navigate this morass. After a couple of hours of digging through the code I kind of get the hang of it (thanks vim!). Now it is time to start walking this code backwards and see if I can generate a CA without having to use openssl "the tool". A few more hours go by and the incomplete man pages, no man pages, poorly written man pages really start to wear on me. No help from google, bing, yahoo etc. The documentation is simply non-existent and what does exist is outdated and does not match reality. Screw it, I am going home!
  58.  
  59. Day 4:
  60.  
  61. I start writing some code based on what I find in openssl "the tool". Progress is painfully slow due to the embarrassingly bad style, indentation and don't get me started about impenetrable #ifdef goo. Speaking of #ifdefs I saw several dangling ones that would eat an instruction; e.g.
  62.  
  63. #ifdef (OMG)
  64. if (moo) {
  65. ...
  66. } else
  67. #endif /* OMG */
  68. yeah();
  69. This is actually the pretty version. The one I ran into was over a couple hundred lines of code with indentation that makes a grown man cry. Lets also get one other thing out of the way. If you think
  70. if (moo)
  71. {
  72. dome_something_dumb();
  73. }
  74. else
  75. {
  76. or_not();
  77. }
  78. or
  79. if ( moo)
  80. {
  81. blah();
  82. }
  83. if (bad)
  84. goto err;
  85. ...
  86. if (0) {
  87. err:
  88. do_something_horrible();
  89. }
  90. is readable I suggest you visit an optometrist. Possibly even a proctologist. Lets look at a few real examples
  91. if ((OBJ_obj2nid(obj) == NID_pkcs9_emailAddress) &&
  92. (str->type != V_ASN1_IA5STRING))
  93. {
  94. BIO_printf(bio_err,"\nemailAddress type needs to be of type IA5STRING\n");
  95. goto err;
  96. }
  97. if ((str->type != V_ASN1_BMPSTRING) && (str->type != V_ASN1_UTF8STRING))
  98. {
  99. j=ASN1_PRINTABLE_type(str->data,str->length);
  100. if ( ((j == V_ASN1_T61STRING) &&
  101. (str->type != V_ASN1_T61STRING)) ||
  102. ((j == V_ASN1_IA5STRING) &&
  103. (str->type == V_ASN1_PRINTABLESTRING)))
  104. {
  105. BIO_printf(bio_err,"\nThe string contains characters that are illegal for the ASN.1 type\n");
  106. goto err;
  107. }
  108. }
  109. Here is an example of a function stack; vim to the rescue!
  110. if (!SSL_CTX_use_certificate_file(ctx, "server/server.crt", SSL_FILETYPE_PEM))
  111. ctrl ]
  112. ...
  113. else if (type == SSL_FILETYPE_PEM)
  114. {
  115. j=ERR_R_PEM_LIB;
  116. x=PEM_read_bio_X509(in,NULL,ctx->default_passwd_callback,ctx->default_passwd_callback_userdata);
  117. ctrl ]
  118. ...
  119. #define PEM_read_bio_X509(bp,x,cb,u) (X509 *)PEM_ASN1_read_bio( \
  120. (char *(*)())d2i_X509,PEM_STRING_X509,bp,(char **)x,cb,u)
  121. ctrl ]
  122. ...
  123. if (!PEM_bytes_read_bio(&data, &len, NULL, name, bp, cb, u))
  124. return NULL;
  125. ctrl ]
  126. ...
  127. if (!PEM_read_bio(bp,&nm,&header,&data,&len)) {
  128. ctrl ]
  129. ...
  130. i=BIO_gets(bp,buf,254);
  131. ctrl ]
  132. ...
  133. i=b->method->bgets(b,in,inl);
  134. That spanned 5 files, 6 indirections and all that to open and fgets the contents of a file. And we still are doing an indirect call. All this work and jumping around when all I wanted is to have a function that can translate a PEM (NOT in a file!!!) cert into a X509 structure. But between the million or so functions nothing handy like that exists; or so I suspect but since there are no docs I really have to guess. I can't rob you guys from this gem either:
  135. #ifndef OPENSSL_NO_STDIO
  136. /*!
  137. * Load CA certs from a file into a ::STACK. Note that it is somewhat misnamed;
  138. * it doesn't really have anything to do with clients (except that a common use
  139. * for a stack of CAs is to send it to the client). Actually, it doesn't have
  140. * much to do with CAs, either, since it will load any old cert.
  141. * \param file the file containing one or more certs.
  142. * \return a ::STACK containing the certs.
  143. */
  144. STACK_OF(X509_NAME) *SSL_load_client_CA_file(const char *file)
  145. {
  146. BIO *in;
  147. X509 *x=NULL;
  148. X509_NAME *xn=NULL;
  149. STACK_OF(X509_NAME) *ret = NULL,*sk;
  150.  
  151. sk=sk_X509_NAME_new(xname_cmp);
  152.  
  153. in=BIO_new(BIO_s_file_internal());
  154.  
  155. if ((sk == NULL) || (in == NULL))
  156. {
  157. SSLerr(SSL_F_SSL_LOAD_CLIENT_CA_FILE,ERR_R_MALLOC_FAILURE);
  158. goto err;
  159. }
  160.  
  161. if (!BIO_read_filename(in,file))
  162. goto err;
  163.  
  164. for (;;)
  165. {
  166. if (PEM_read_bio_X509(in,&x,NULL,NULL) == NULL)
  167. break;
  168. if (ret == NULL)
  169. {
  170. ret = sk_X509_NAME_new_null();
  171. if (ret == NULL)
  172. {
  173. SSLerr(SSL_F_SSL_LOAD_CLIENT_CA_FILE,ERR_R_MALLOC_FAILURE);
  174. goto err;
  175. }
  176. }
  177. if ((xn=X509_get_subject_name(x)) == NULL) goto err;
  178. /* check for duplicates */
  179. xn=X509_NAME_dup(xn);
  180. if (xn == NULL) goto err;
  181. if (sk_X509_NAME_find(sk,xn) >= 0)
  182. X509_NAME_free(xn);
  183. else
  184. {
  185. sk_X509_NAME_push(sk,xn);
  186. sk_X509_NAME_push(ret,xn);
  187. }
  188. }
  189.  
  190. if (0)
  191. {
  192. err:
  193. if (ret != NULL) sk_X509_NAME_pop_free(ret,X509_NAME_free);
  194. ret=NULL;
  195. }
  196. if (sk != NULL) sk_X509_NAME_free(sk);
  197. if (in != NULL) BIO_free(in);
  198. if (x != NULL) X509_free(x);
  199. if (ret != NULL)
  200. ERR_clear_error();
  201. return(ret);
  202. }
  203. #endif
  204. Wow! that one does it all! unreadable, lots of indirection and no clear direction as to what the function is trying to achieve. Got to love the if (0) construct! I mean that obviously wins all the beauty, aesthetics & NIH awards. You have to be overjoyed to know that this type of code runs a lot of our "secure" internet.
  205. Silly me to just want to have a function to read certs from LDAP or memory so that I can write the LDAP code myself. Not much code got written, I need to go home and go into some sort of drunken stooper.
  206.  
  207. Day 5:
  208.  
  209. This is starting to piss me off! Armed with a fresh headache I get with the coding part. After a couple of hours of reading and rereading some openssl "the tool" code I came up with this:
  210.  
  211. int
  212. create_ca(char *retstr, size_t retlen)
  213. {
  214. int rv = 1;
  215. int days = 365 * 10;
  216. char *password = NULL;
  217. EVP_PKEY pkey, *tmppkey = NULL;
  218. BIGNUM bn;
  219. RSA *rsa = NULL;
  220. X509_REQ *req = NULL;
  221. X509_NAME *subj;
  222. X509 *x509 = NULL;
  223. BIO *out = NULL;
  224.  
  225. /* generate private key */
  226. if ((rsa = RSA_new()) == NULL)
  227. ERROR_OUT(ERR_SSL, done);
  228. bzero(&bn, sizeof bn);
  229. if (BN_set_word(&bn, 0x10001) == 0)
  230. ERROR_OUT(ERR_SSL, done);
  231. if (RSA_generate_key_ex(rsa, 1024, &bn, NULL) == 0)
  232. ERROR_OUT(ERR_SSL, done);
  233. bzero(&pkey, sizeof pkey);
  234. if (EVP_PKEY_assign_RSA(&pkey, rsa) == 0)
  235. ERROR_OUT(ERR_SSL, done);
  236.  
  237. /* setup req for certificate */
  238. if ((req = X509_REQ_new()) == NULL)
  239. ERROR_OUT(ERR_SSL, done);
  240. if (X509_REQ_set_version(req, 0) == 0)
  241. ERROR_OUT(ERR_SSL, done);
  242. subj = X509_REQ_get_subject_name(req);
  243. if (validate_canew(subj, &password)) {
  244. snprintf(last_error, sizeof last_error,
  245. "validate_canew failed");
  246. ERROR_OUT(ERR_OWN, done);
  247. }
  248. /* set public key to req */
  249. if (X509_REQ_set_pubkey(req, &pkey) == 0)
  250. ERROR_OUT(ERR_SSL, done);
  251.  
  252. /* generate 509 cert */
  253. if ((x509 = X509_new()) == NULL)
  254. ERROR_OUT(ERR_SSL, done);
  255. bzero(&bn, sizeof bn);
  256. if (BN_pseudo_rand(&bn, 64 /* bits */, 0, 0) == 0)
  257. ERROR_OUT(ERR_SSL, done);
  258. if (BN_to_ASN1_INTEGER(&bn, X509_get_serialNumber(x509)) == 0)
  259. ERROR_OUT(ERR_SSL, done);
  260. if (X509_set_issuer_name(x509, X509_REQ_get_subject_name(req)) == 0)
  261. ERROR_OUT(ERR_SSL, done);
  262. if (X509_gmtime_adj(X509_get_notBefore(x509), 0) == 0)
  263. ERROR_OUT(ERR_SSL, done);
  264. if (days == 0) {
  265. snprintf(last_error, sizeof last_error,
  266. "not enough days for certificate");
  267. ERROR_OUT(ERR_OWN, done);
  268. }
  269. days *= 60 * 60 * 24;
  270. if (X509_gmtime_adj(X509_get_notAfter(x509), days) == 0)
  271. ERROR_OUT(ERR_SSL, done);
  272. if (X509_set_subject_name(x509, X509_REQ_get_subject_name(req)) == 0)
  273. ERROR_OUT(ERR_SSL, done);
  274. if ((tmppkey = X509_REQ_get_pubkey(req)) == NULL)
  275. ERROR_OUT(ERR_SSL, done);
  276. if (X509_set_pubkey(x509, tmppkey) == 0)
  277. ERROR_OUT(ERR_SSL, done);
  278. if (X509_sign(x509, &pkey, EVP_sha1()) == 0)
  279. ERROR_OUT(ERR_SSL, done);
  280.  
  281. /* write private key */
  282. out = BIO_new(BIO_s_file());
  283. if (BIO_write_filename(out, CA_PKEY) <= 0)
  284. ERROR_OUT(ERR_SSL, done);
  285. if (chmod(CA_PKEY, S_IRWXU))
  286. ERROR_OUT(ERR_LIBC, done);
  287. if (PEM_write_bio_PrivateKey(out, &pkey, EVP_des_ede3_cbc(), NULL, 0,
  288. NULL, password) == 0)
  289. ERROR_OUT(ERR_SSL, done);
  290. BIO_free_all(out);
  291.  
  292. /* write cert */
  293. out = BIO_new(BIO_s_file());
  294. if (BIO_write_filename(out, CA_CERT) <= 0)
  295. ERROR_OUT(ERR_SSL, done);
  296. if (PEM_write_bio_X509(out, x509) == 0)
  297. ERROR_OUT(ERR_SSL, done);
  298. BIO_free_all(out);
  299.  
  300. rv = 0;
  301. done:
  302. if (tmppkey)
  303. EVP_PKEY_free(tmppkey);
  304. if (x509)
  305. X509_free(x509);
  306. if (req)
  307. X509_REQ_free(req);
  308. if (rsa)
  309. RSA_free(rsa);
  310.  
  311. return (rv);
  312. }
  313. As you can see I create an awful mechanism to at least get some sort of usable fault stack to trace errors. Here is the macro in its full horror:
  314. /* errors */
  315. #define ERR_LIBC (0)
  316. #define ERR_SSL (1)
  317. #define ERR_OWN (2)
  318.  
  319. #define ERROR_OUT(e, g) do { push_error(__FILE__, __FUNCTION__, __LINE__, e); goto g; } while(0)
  320. Dear $DEITY I beg your forgiveness for I have sinned.
  321. Let me show the other bits to make this work just for completions sake and to hope I can help another lost soul that has to put up with this poo. The functions that play with this garbage:
  322.  
  323. char *
  324. geterror(int et)
  325. {
  326. char *es;
  327.  
  328. switch (et) {
  329. case ERR_LIBC:
  330. strlcpy(last_error, strerror(errno), sizeof last_error);
  331. break;
  332. case ERR_SSL:
  333. es = (char *)ERR_lib_error_string(ERR_get_error());
  334. if (es)
  335. strlcpy(last_error, es, sizeof last_error);
  336. else
  337. strlcpy(last_error, "unknown SSL error",
  338. sizeof last_error);
  339. break;
  340. default:
  341. strlcpy(last_error, "unknown error", sizeof last_error);
  342. /* FALLTHROUGH */
  343. case ERR_OWN:
  344. break;
  345. }
  346.  
  347. return (last_error);
  348. }
  349.  
  350. void
  351. push_error(char *file, char *func, int line, int et)
  352. {
  353. struct error *ce;
  354.  
  355. if ((ce = calloc(1, sizeof *ce)) == NULL)
  356. fatal("push_error ce");
  357. if ((ce->file = strdup(file)) == NULL)
  358. fatal("push_error ce->file");
  359. if ((ce->func = strdup(func)) == NULL)
  360. fatal("push_error ce->func");
  361. if ((ce->errstr = strdup(geterror(et))) == NULL)
  362. fatal("push_error ce->errstr");
  363. ce->line = line;
  364.  
  365. SLIST_INSERT_HEAD(&ces, ce, dlink);
  366. }
  367.  
  368. Here are the remaining utility functions to make it all "work":
  369. int
  370. cert_find_put(char *entry, X509_NAME *subj, ssize_t min, ssize_t max)
  371. {
  372. struct valnode *v;
  373. int rv = 1;
  374.  
  375. v = find_valtree(entry);
  376. if (v && v->length > 0) {
  377. if (min != -1 && v->length < min) {
  378. snprintf(last_error, sizeof last_error,
  379. "%s minimum constraint not met %lu < %lu",
  380. entry, v->length, min);
  381. ERROR_OUT(ERR_OWN, done);
  382. }
  383. if (max != -1 && v->length > max) {
  384. snprintf(last_error, sizeof last_error,
  385. "%s maximum constraint not met %lu > %lu",
  386. entry, v->length, max);
  387. ERROR_OUT(ERR_OWN, done);
  388. }
  389. if (X509_NAME_add_entry_by_txt(subj, entry, MBSTRING_ASC,
  390. v->value, -1, -1, 0) == 0)
  391. ERROR_OUT(ERR_SSL, done);
  392. } else {
  393. log_debug("cert_find_put: %s not found", entry);
  394. goto done;
  395. }
  396.  
  397. rv = 0;
  398. done:
  399. return (rv);
  400. }
  401.  
  402. int
  403. validate_canew(X509_NAME *subj, char **pwd)
  404. {
  405. struct valnode *password, *password2;
  406. int rv = 1;
  407.  
  408. password = find_valtree("password");
  409. password2 = find_valtree("password2");
  410.  
  411. if (password && password2) {
  412. if (strcmp(password->value, password2->value) ||
  413. password->length == 0) {
  414. snprintf(last_error, sizeof last_error,
  415. "invalid password");
  416. ERROR_OUT(ERR_OWN, done);
  417. }
  418. *pwd = password->value;
  419. }
  420. if (password == NULL && password2 == NULL) {
  421. snprintf(last_error, sizeof last_error,
  422. "password can't be NULL");
  423. ERROR_OUT(ERR_OWN, done);
  424. }
  425.  
  426. if (cert_find_put("C", subj, 2, 2)) {
  427. snprintf(last_error, sizeof last_error,
  428. "invalid country");
  429. ERROR_OUT(ERR_OWN, done);
  430. }
  431. cert_find_put("ST", subj, -1, -1);
  432. cert_find_put("L", subj, -1, -1);
  433. cert_find_put("O", subj, -1, -1);
  434. cert_find_put("OU", subj, -1, -1);
  435. cert_find_put("CN", subj, -1, -1);
  436. cert_find_put("emailAddress", subj, -1, -1);
  437.  
  438. rv = 0;
  439. done:
  440. return (rv);
  441. }
  442. Jubilation! We have a CA OMG!!!oneONE!!!111~ Time to go home!
  443. At home I sit in the shower and cry a little, WAIT, is that blood???
  444. Day 6:
  445.  
  446. I'll get to writing stuff into LDAP later. I need to work on something else for a while. So next up, a client/server app that negotiates SSL/TLS. First I try various examples on the net.
  447.  
  448. Big bag of FAIL
  449.  
  450. Well, then we'll look at the man pages, I mean they totally come with an example!
  451.  
  452. Second big bag of FAIL
  453.  
  454. Farting around with crap I found on the net + example + a lot of time.
  455.  
  456. Third big bag of FAIL
  457.  
  458. Enough, I am going home.
  459.  
  460. Day 7:
  461.  
  462. Alright, time to go back into my by now favorite piece of code! openssl "the tool" has s_server and s_client and if you push the buttons it sort of seems to work. These are the magic commands I came up with:
  463.  
  464. openssl s_server -CAfile ca/ca.crt -cert server/server.crt -key server/private/server.key -Verify 1
  465. openssl s_client -CAfile ca/ca.crt -cert client/client.crt -key client/private/client.key
  466. That connects over SSL/TLS according to it and it seemed ok in tcpdump as well. So lets start coding! I'll present you here with my test code, again I am hoping to do other folks a favor and hope that a few murders can be averted. First up the server:
  467. #include <stdio.h>
  468. #include <stdlib.h>
  469. #include <err.h>
  470.  
  471. #include <sys/types.h>
  472. #include <sys/socket.h>
  473.  
  474. #include <netinet/in.h>
  475.  
  476. #include "openssl/bio.h"
  477. #include "openssl/ssl.h"
  478. #include "openssl/err.h"
  479.  
  480. void
  481. fatalx(char *s)
  482. {
  483. ERR_print_errors_fp(stderr);
  484. errx(1, s);
  485. }
  486.  
  487. int
  488. main(int argc, char *argv[])
  489. {
  490. SSL_CTX *ctx;
  491. BIO *sbio;
  492. SSL *ssl;
  493. int sock, s, r, val = -1;
  494. struct sockaddr_in sin;
  495.  
  496. SSL_load_error_strings();
  497. OpenSSL_add_ssl_algorithms();
  498.  
  499. ctx = SSL_CTX_new(SSLv23_server_method());
  500. if (ctx == NULL)
  501. fatalx("ctx");
  502.  
  503. if (!SSL_CTX_load_verify_locations(ctx, "ca/ca.crt", NULL))
  504. fatalx("verify");
  505. SSL_CTX_set_client_CA_list(ctx, SSL_load_client_CA_file("ca/ca.crt"));
  506.  
  507. if (!SSL_CTX_use_certificate_file(ctx, "server/server.crt", SSL_FILETYPE_PEM))
  508. fatalx("cert");
  509. if (!SSL_CTX_use_PrivateKey_file(ctx, "server/private/server.key", SSL_FILETYPE_PEM))
  510. fatalx("key");
  511. if (!SSL_CTX_check_private_key(ctx))
  512. fatalx("cert/key");
  513.  
  514. SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
  515. SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);
  516. SSL_CTX_set_verify_depth(ctx, 1);
  517.  
  518. /* setup socket */
  519. if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
  520. err(1, "socket");
  521.  
  522. bzero(&sin, sizeof sin);
  523. sin.sin_addr.s_addr = INADDR_ANY;
  524. sin.sin_family = AF_INET;
  525. sin.sin_port = htons(4433);
  526. setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof val);
  527.  
  528. if (bind(sock, (struct sockaddr *)&sin, sizeof sin) == -1)
  529. err(1, "bind");
  530. listen(sock, 0);
  531.  
  532. for (;;) {
  533. if ((s = accept(sock, 0, 0)) == -1)
  534. err(1, "accept");
  535.  
  536. sbio = BIO_new_socket(s, BIO_NOCLOSE);
  537. ssl = SSL_new(ctx);
  538. SSL_set_bio(ssl, sbio, sbio);
  539.  
  540. if ((r = SSL_accept(ssl)) == -1)
  541. fatalx("SSL_accept");
  542.  
  543. printf("handle it!\n");
  544. }
  545.  
  546. return (0);
  547. }
  548. and the client:
  549. #include <stdio.h>
  550. #include <stdlib.h>
  551. #include <err.h>
  552.  
  553. #include <sys/types.h>
  554. #include <sys/socket.h>
  555.  
  556. #include <netinet/in.h>
  557. #include <netdb.h>
  558.  
  559. #include "openssl/bio.h"
  560. #include "openssl/ssl.h"
  561. #include "openssl/err.h"
  562.  
  563. void
  564. fatalx(char *s)
  565. {
  566. ERR_print_errors_fp(stderr);
  567. errx(1, s);
  568. }
  569.  
  570. int
  571. main(int argc, char *argv[])
  572. {
  573. SSL_CTX *ctx;
  574. BIO *sbio;
  575. SSL *ssl;
  576. struct sockaddr_in addr;
  577. struct hostent *hp;
  578. int sock;
  579.  
  580.  
  581. SSL_load_error_strings();
  582. OpenSSL_add_ssl_algorithms();
  583.  
  584. ctx = SSL_CTX_new(SSLv23_client_method());
  585. if (ctx == NULL)
  586. fatalx("ctx");
  587.  
  588. if (!SSL_CTX_load_verify_locations(ctx, "ca/ca.crt", NULL))
  589. fatalx("verify");
  590.  
  591. if (!SSL_CTX_use_certificate_file(ctx, "client/client.crt", SSL_FILETYPE_PEM))
  592. fatalx("cert");
  593. if (!SSL_CTX_use_PrivateKey_file(ctx, "client/private/client.key", SSL_FILETYPE_PEM))
  594. fatalx("key");
  595. if (!SSL_CTX_check_private_key(ctx))
  596. fatalx("cert/key");
  597.  
  598. SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
  599. SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
  600. SSL_CTX_set_verify_depth(ctx, 1);
  601.  
  602. /* setup connection */
  603. if ((hp = gethostbyname("localhost")) == NULL)
  604. err(1, "gethostbyname");
  605.  
  606. bzero(&addr, sizeof addr);
  607. addr.sin_addr = *(struct in_addr *)hp->h_addr_list[0];
  608. addr.sin_family = AF_INET;
  609. addr.sin_port = htons(4433);
  610.  
  611. if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
  612. err(1, "socket");
  613. if (connect(sock, (struct sockaddr *)&addr, sizeof addr) == -1)
  614. err(1, "connect");
  615.  
  616. /* go do ssl magic */
  617. ssl = SSL_new(ctx);
  618. sbio = BIO_new_socket(sock, BIO_NOCLOSE);
  619. SSL_set_bio(ssl, sbio, sbio);
  620.  
  621. if (SSL_connect(ssl) <= 0)
  622. fatalx("SSL_connect");
  623.  
  624. if (SSL_get_verify_result(ssl) != X509_V_OK)
  625. fatalx("cert");
  626.  
  627. return (0);
  628. }
  629. Not my best work but it works and someone might be helped by this. Going home!
  630. Day 8:
  631.  
  632. Looking some more on how to make those damned files work within LDAP. Between meetings and other lame things I gave up and wrote this rant instead. I'll continue to update this as I make more progress. I shall overcome the excrement flinging ape that is OpenSSL.
  633.  
  634. The opinions of the author expressed herein do not necessarily state or reflect those of anyone else.
  635. Opinion and code © 2009 Marco Peereboom.
  636. Code snippets from the OpenSSL project are © 1998-2009 The OpenSSL Project.
  637.  
  638. $assl: openssl.html,v 1.3 2009/08/24 18:45:53 marco Exp $
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement