Created
December 17, 2012 11:54
-
-
Save richo/4317715 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;;;; openssl.scm | |
;;;; Bindings to the OpenSSL SSL/TLS library | |
(module openssl | |
( | |
ssl-connect | |
ssl-make-client-context | |
ssl-client-context? | |
ssl-listen | |
ssl-close | |
ssl-port? | |
ssl-port->tcp-port | |
ssl-listener? | |
ssl-listener? | |
ssl-listener-port | |
ssl-listener-fileno | |
ssl-accept-ready? | |
ssl-accept | |
ssl-handshake-timeout | |
ssl-shutdown-timeout | |
ssl-load-certificate-chain! | |
ssl-load-private-key! | |
ssl-set-verify! | |
ssl-load-verify-root-certificates! | |
ssl-load-suggested-certificate-authorities! | |
ssl-peer-verified? | |
ssl-peer-subject-name ssl-peer-issuer-name | |
ssl-make-i/o-ports | |
net-unwrap-tcp-ports) | |
(import scheme chicken foreign ports) | |
(declare | |
(usual-integrations) | |
(no-procedure-checks-for-usual-bindings) | |
(bound-to-procedure | |
##sys#update-errno | |
##sys#signal-hook | |
##sys#string-append | |
##sys#tcp-port->fileno | |
##sys#current-thread | |
##sys#size | |
##sys#setslot | |
##sys#check-string | |
##sys#expand-home-path)) | |
(use srfi-18 tcp) | |
#> | |
#include <errno.h> | |
#ifdef _WIN32 | |
#ifdef _MSC_VER | |
#include <winsock2.h> | |
#else | |
#include <ws2tcpip.h> | |
#endif | |
#include <openssl/rand.h> | |
#else | |
#define closesocket close | |
#endif | |
#ifdef ECOS | |
#include <sys/sockio.h> | |
#else | |
#include <unistd.h> | |
#endif | |
#include <openssl/err.h> | |
#include <openssl/ssl.h> | |
<# | |
(foreign-code #<<EOF | |
ERR_load_crypto_strings(); | |
SSL_load_error_strings(); | |
SSL_library_init(); | |
#ifdef _WIN32 | |
RAND_screen(); | |
#endif | |
EOF | |
) | |
;;; support routines | |
(define-foreign-variable strerror c-string "strerror(errno)") | |
(define ssl-handshake-timeout (make-parameter 120000)) | |
(define ssl-shutdown-timeout (make-parameter 120000)) | |
(define (net-close-socket fd) | |
(when ((foreign-lambda bool "closesocket" int) fd) | |
(##sys#update-errno) | |
(##sys#signal-hook | |
network-error: 'net-close-socket | |
(##sys#string-append "can not close socket - " strerror) | |
fd))) | |
(define (net-unwrap-tcp-ports tcp-in tcp-out) | |
(let ((fd (##sys#tcp-port->fileno tcp-in))) | |
(tcp-abandon-port tcp-in) | |
(tcp-abandon-port tcp-out) | |
fd)) | |
(define (ssl-abort loc sym . args) | |
(let ((err ((foreign-lambda unsigned-long "ERR_get_error")))) | |
(abort | |
(make-composite-condition | |
(make-property-condition | |
'exn | |
'message | |
(string-append | |
(if sym | |
(symbol->string sym) | |
"error") | |
": library=" | |
(or | |
((foreign-lambda c-string "ERR_lib_error_string" unsigned-long) | |
err) | |
"<unknown>") | |
", function=" | |
(or | |
((foreign-lambda c-string "ERR_func_error_string" unsigned-long) | |
err) | |
"<unknown>") | |
", reason=" | |
(or | |
((foreign-lambda c-string "ERR_reason_error_string" unsigned-long) | |
err) | |
"<unknown>")) | |
'location | |
loc | |
'arguments args) | |
(make-property-condition | |
'i/o) | |
(make-property-condition | |
'net) | |
(make-property-condition | |
'openssl | |
'status | |
sym))))) | |
(define ssl-ctx-free (foreign-lambda void "SSL_CTX_free" c-pointer)) | |
(define (ssl-ctx-new protocol server) | |
(let ((ctx | |
((foreign-lambda* | |
c-pointer ((c-pointer method)) | |
"SSL_CTX *ctx;" | |
"if ((ctx = SSL_CTX_new((SSL_METHOD *)method)))\n" | |
" SSL_CTX_set_mode(ctx, SSL_MODE_ENABLE_PARTIAL_WRITE | " | |
" SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);\n" | |
"return(ctx);\n") | |
(case protocol | |
((sslv2-or-v3) | |
(if server | |
((foreign-lambda c-pointer "SSLv23_server_method")) | |
((foreign-lambda c-pointer "SSLv23_client_method")))) | |
((sslv2) | |
(if server | |
((foreign-lambda c-pointer "SSLv2_server_method")) | |
((foreign-lambda c-pointer "SSLv2_client_method")))) | |
((sslv3) | |
(if server | |
((foreign-lambda c-pointer "SSLv3_server_method")) | |
((foreign-lambda c-pointer "SSLv3_client_method")))) | |
((tls) | |
(if server | |
((foreign-lambda c-pointer "TLSv1_server_method")) | |
((foreign-lambda c-pointer "TLSv1_client_method")))) | |
(else | |
(abort | |
(make-composite-condition | |
(make-property-condition | |
'exn | |
'message "invalid SSL/TLS connection protocol" | |
'location 'ssl-ctx-new | |
'arguments (list protocol)) | |
(make-property-condition | |
'type)))))))) | |
(unless ctx (ssl-abort 'ssl-ctx-new #f)) | |
(set-finalizer! ctx ssl-ctx-free) | |
ctx)) | |
(define (ssl-new ctx) | |
(cond | |
(((foreign-lambda c-pointer "SSL_new" c-pointer) ctx) | |
=> values) | |
(else | |
(ssl-abort 'ssl-new #f)))) | |
(define ssl-free (foreign-lambda void "SSL_free" c-pointer)) | |
(define (ssl-result-or-abort loc ssl ret allow-i/o? . args) | |
(call-with-current-continuation | |
(lambda (q) | |
(let ((sym | |
(let ((x ((foreign-lambda int "SSL_get_error" c-pointer int) | |
ssl ret))) | |
(cond | |
((eq? x (foreign-value "SSL_ERROR_NONE" int)) | |
(q ret)) | |
((eq? x (foreign-value "SSL_ERROR_ZERO_RETURN" int)) | |
'zero-return) | |
((eq? x (foreign-value "SSL_ERROR_WANT_READ" int)) | |
(if allow-i/o? | |
(q 'want-read) | |
'want-read)) | |
((eq? x (foreign-value "SSL_ERROR_WANT_WRITE" int)) | |
(if allow-i/o? | |
(q 'want-write) | |
'want-write)) | |
((eq? x (foreign-value "SSL_ERROR_WANT_CONNECT" int)) | |
'want-connect) | |
((eq? x (foreign-value "SSL_ERROR_WANT_ACCEPT" int)) | |
'want-accept) | |
((eq? x (foreign-value "SSL_ERROR_WANT_X509_LOOKUP" int)) | |
'want-X509-lookup) | |
((eq? x (foreign-value "SSL_ERROR_SYSCALL" int)) | |
'syscall) | |
((eq? x (foreign-value "SSL_ERROR_SSL" int)) | |
'ssl) | |
(else | |
#f))))) | |
(apply ssl-abort loc sym args))))) | |
(define (ssl-set-fd! ssl fd) | |
(ssl-result-or-abort | |
'ssl-set-fd! ssl | |
((foreign-lambda int "SSL_set_fd" c-pointer int) ssl fd) #f | |
fd) | |
(void)) | |
(define (ssl-shutdown ssl) | |
(let ((ret | |
((foreign-lambda* | |
scheme-object ((c-pointer ssl)) | |
"int ret;\n" | |
"switch (ret = SSL_shutdown((SSL *)ssl)) {\n" | |
"case 0: return(C_SCHEME_FALSE);\n" | |
"case 1: return(C_SCHEME_TRUE);\n" | |
"default: return(C_fix(ret));\n" | |
"}\n") ssl))) | |
(if (fixnum? ret) | |
(ssl-result-or-abort 'ssl-shutdown ssl ret #t) | |
ret))) | |
(define (ssl-get-char ssl) | |
(let ((ret | |
((foreign-lambda* | |
scheme-object ((c-pointer ssl)) | |
"char ch;\n" | |
"int ret;\n" | |
"switch (ret = SSL_read((SSL *)ssl, &ch, 1)) {\n" | |
"case 0: return(C_SCHEME_END_OF_FILE);\n" | |
"case 1: return(C_make_character(ch));\n" | |
"default: return(C_fix(ret));\n" | |
"}\n") | |
ssl))) | |
(if (fixnum? ret) | |
(ssl-result-or-abort 'ssl-get-char ssl ret #t) | |
ret))) | |
(define (ssl-write ssl buffer offset size) | |
(ssl-result-or-abort | |
'ssl-write ssl | |
((foreign-lambda* | |
int ((c-pointer ssl) (scheme-pointer buf) (int offset) (int size)) | |
"return(SSL_write((SSL *)ssl, (char *)buf + offset, size));\n") | |
ssl buffer offset size) | |
#t)) | |
(define-record-type ssl-port-data | |
(ssl-make-port-data startup ssl tcp-port) | |
ssl-port-data? | |
(startup ssl-port-data-startup) | |
(ssl ssl-port-data-ssl) | |
(tcp-port ssl-port-data-tcp-port)) | |
(define (ssl-port? obj) | |
(and (port? obj) (eq? (##sys#slot obj 10) 'ssl-socket))) | |
(define (ssl-port-startup p) | |
(when (ssl-port? p) | |
((ssl-port-data-startup (##sys#slot p 11))))) | |
(define (ssl-port->ssl p) | |
(if (ssl-port? p) | |
(ssl-port-data-ssl (##sys#slot p 11)) | |
(abort | |
(make-composite-condition | |
(make-property-condition | |
'exn | |
'location 'ssl-port->ssl-context | |
'message "expected an ssl port, got" | |
'arguments (list p)) | |
(make-property-condition | |
'type))))) | |
(define (ssl-port->tcp-port p) | |
(if (ssl-port? p) | |
(ssl-port-data-tcp-port (##sys#slot p 11)) | |
(abort | |
(make-composite-condition | |
(make-property-condition | |
'exn | |
'location 'ssl-port->tcp-port | |
'message "expected an ssl port, got" | |
'arguments (list p)) | |
(make-property-condition | |
'type))))) | |
(define (ssl-do-handshake ssl) | |
(ssl-result-or-abort 'ssl-do-handshake ssl | |
((foreign-lambda int "SSL_do_handshake" c-pointer) ssl) #t)) | |
(define (ssl-call/timeout loc proc fd timeout timeout-message) | |
(let loop ((res (proc))) | |
(case res | |
((want-read) | |
(when timeout | |
(##sys#thread-block-for-timeout! | |
##sys#current-thread (+ (current-milliseconds) timeout))) | |
(##sys#thread-block-for-i/o! ##sys#current-thread fd #:input) | |
(thread-yield!) | |
(if (##sys#slot ##sys#current-thread 13) | |
(##sys#signal-hook | |
#:network-timeout-error loc timeout-message timeout fd) | |
(loop (proc)))) | |
((want-write) | |
(when timeout | |
(##sys#thread-block-for-timeout! | |
##sys#current-thread (+ (current-milliseconds) timeout))) | |
(##sys#thread-block-for-i/o! ##sys#current-thread fd #:output) | |
(thread-yield!) | |
(if (##sys#slot ##sys#current-thread 13) | |
(##sys#signal-hook | |
#:network-timeout-error loc timeout-message timeout fd) | |
(loop (proc)))) | |
(else res)))) | |
(define (ssl-make-i/o-ports ctx fd ssl tcp-in tcp-out) | |
;; note that the ctx parameter is never used but it is passed in order | |
;; to be present in the closure data of the various port functions | |
;; so it isn't garbage collected before the ports are all gone | |
(let ((in-open? #f) (out-open? #f) | |
(mutex (make-mutex 'ssl-mutex))) | |
(define (startup) | |
(dynamic-wind | |
(lambda () | |
(mutex-lock! mutex)) | |
(lambda () | |
(when (not ssl) | |
(error "SSL socket already closed")) | |
(unless (or in-open? out-open?) | |
(let ((success? #f)) | |
(dynamic-wind | |
void | |
(lambda () | |
(ssl-set-fd! ssl fd) | |
(ssl-call/timeout 'ssl-do-handshake | |
(lambda () (ssl-do-handshake ssl)) | |
fd (ssl-handshake-timeout) | |
"SSL handshake operation timed out") | |
(set! in-open? #t) | |
(set! out-open? #t) | |
(set! success? #t)) | |
(lambda () | |
(unless success? | |
(ssl-free ssl) | |
(set! ssl #f) | |
(net-close-socket fd))))))) | |
(lambda () | |
(mutex-unlock! mutex)))) | |
(define (shutdown) | |
(unless (or in-open? out-open?) | |
(set! ctx #f) ;; ensure that this reference is lost | |
(dynamic-wind | |
void | |
(lambda () | |
(ssl-call/timeout 'ssl-shutdown | |
(lambda () (ssl-shutdown ssl)) | |
fd (ssl-shutdown-timeout) | |
"SSL shutdown operation timed out")) | |
(lambda () | |
(ssl-free ssl) | |
(net-close-socket fd))))) | |
(let ((in | |
(let ((buffer #f)) | |
(make-input-port | |
;; read | |
(lambda () | |
(startup) | |
(unless buffer | |
(set! buffer | |
(ssl-call/timeout 'ssl-get-char | |
(lambda () (ssl-get-char ssl)) | |
fd (tcp-read-timeout) | |
"SSL read timed out"))) | |
(if buffer | |
(let ((ch buffer)) | |
(set! buffer #f) | |
ch) | |
#!eof)) | |
;; ready? | |
(lambda () | |
(startup) | |
(or buffer | |
(let ((ret (ssl-get-char ssl))) | |
(case ret | |
((want-read want-write) | |
#f) | |
(else | |
(set! buffer ret) | |
#t))))) | |
;; close | |
(lambda () | |
(startup) | |
(set! in-open? #f) | |
(shutdown)) | |
;; peek | |
(lambda () | |
(startup) | |
(unless buffer | |
(set! buffer (ssl-call/timeout 'ssl-peek-char | |
(lambda () (ssl-get-char ssl)) | |
fd (tcp-read-timeout) | |
"SSL read timed out"))) | |
(if buffer | |
buffer | |
#!eof))))) | |
(out | |
(make-output-port | |
;; write | |
(lambda (buffer) | |
(startup) | |
(when (> (##sys#size buffer) 0) ; Undefined behaviour for 0 bytes! | |
(let loop ((offset 0) (size (##sys#size buffer))) | |
(let ((ret (ssl-call/timeout | |
'ssl-peek-char | |
(lambda () (ssl-write ssl buffer offset size)) | |
fd (tcp-write-timeout) "SSL write timed out"))) | |
(when (fx< ret size) ; Partial write | |
(loop (fx+ offset ret) (fx- size ret))))))) | |
;; close | |
(lambda () | |
(startup) | |
(set! out-open? #f) | |
(shutdown))))) | |
(##sys#setslot in 3 "(ssl)") | |
(##sys#setslot out 3 "(ssl)") | |
;; first "reserved" slot | |
;; Slot 7 should probably stay 'custom | |
(##sys#setslot in 10 'ssl-socket) | |
(##sys#setslot out 10 'ssl-socket) | |
;; second "reserved" slot | |
(##sys#setslot in 11 (ssl-make-port-data startup ssl tcp-in)) | |
(##sys#setslot out 11 (ssl-make-port-data startup ssl tcp-out)) | |
(values in out)))) | |
(define (ssl-unwrap-context obj) | |
(cond | |
((ssl-client-context? obj) | |
(ssl-unwrap-client-context obj)) | |
((ssl-listener? obj) | |
(ssl-unwrap-listener-context obj)) | |
(else | |
(abort | |
(make-composite-condition | |
(make-property-condition | |
'exn | |
'location 'ssl-unwrap-context | |
'message "expected an ssl-client-context or ssl-listener, got" | |
'arguments (list obj)) | |
(make-property-condition | |
'type)))))) | |
;;; exported routines | |
;; create SSL client context | |
(define-record-type ssl-client-context | |
(ssl-wrap-client-context context) | |
ssl-client-context? | |
(context ssl-unwrap-client-context)) | |
(define (ssl-make-client-context #!optional (protocol 'sslv2-or-v3)) | |
(ssl-wrap-client-context (ssl-ctx-new protocol #f))) | |
(define ssl-set-connect-state! (foreign-lambda void "SSL_set_connect_state" c-pointer)) | |
;; connect to SSL server | |
(define (ssl-connect hostname #!optional port (ctx 'sslv2-or-v3)) | |
(receive (tcp-in tcp-out) | |
(tcp-connect hostname port) | |
(let* ((fd (net-unwrap-tcp-ports tcp-in tcp-out)) | |
(ctx | |
(if (ssl-client-context? ctx) | |
(ssl-unwrap-client-context ctx) | |
(ssl-ctx-new ctx #f))) | |
(ssl | |
(ssl-new ctx))) | |
(ssl-set-connect-state! ssl) | |
(ssl-make-i/o-ports ctx fd ssl tcp-in tcp-out)))) | |
;; create listener/SSL server context | |
(define-record-type ssl-listener | |
(ssl-wrap-listener context listener) | |
ssl-listener? | |
(context ssl-unwrap-listener-context) | |
(listener ssl-unwrap-listener)) | |
(define (ssl-listen port #!optional (backlog 4) (hostname #f) (ctx 'sslv2-or-v3)) | |
(ssl-wrap-listener | |
(if (ssl-client-context? ctx) | |
(ssl-unwrap-client-context ctx) | |
(ssl-ctx-new ctx #t)) | |
(tcp-listen port backlog hostname))) | |
;; shutdown a SSL server | |
(define (ssl-close listener) | |
(tcp-close (ssl-unwrap-listener listener))) | |
;; return the port number this listener is operating on | |
(define (ssl-listener-port listener) | |
(tcp-listener-port (ssl-unwrap-listener listener))) | |
;; get the underlying socket descriptor number for an SSL listener | |
(define (ssl-listener-fileno listener) | |
(tcp-listener-fileno (ssl-unwrap-listener listener))) | |
;; check whether an incoming connection is pending | |
(define (ssl-accept-ready? listener) | |
(tcp-accept-ready? (ssl-unwrap-listener listener))) | |
(define ssl-set-accept-state! (foreign-lambda void "SSL_set_accept_state" c-pointer)) | |
;; accept a connection from an SSL listener | |
(define (ssl-accept listener) | |
(receive (tcp-in tcp-out) | |
(tcp-accept (ssl-unwrap-listener listener)) | |
(let* ((fd (net-unwrap-tcp-ports tcp-in tcp-out)) | |
(ctx (ssl-unwrap-listener-context listener)) | |
(ssl (ssl-new ctx))) | |
(ssl-set-accept-state! ssl) | |
(ssl-make-i/o-ports ctx fd ssl tcp-in tcp-out)))) | |
;; load identifying certificate chain into SSL context | |
(define (ssl-load-certificate-chain! obj pathname) | |
(##sys#check-string pathname) | |
(unless (eq? | |
((foreign-lambda | |
int "SSL_CTX_use_certificate_chain_file" c-pointer c-string) | |
(ssl-unwrap-context obj) (##sys#expand-home-path pathname)) | |
1) | |
(ssl-abort 'ssl-load-certificate-chain! #f pathname))) | |
;; load the private key for the identifying certificate chain | |
(define (ssl-load-private-key! obj pathname #!optional (rsa? #t) (asn1? #f)) | |
(##sys#check-string pathname) | |
(unless (eq? | |
((foreign-lambda* | |
int ((c-pointer ctx) (c-string path) (bool rsa) (bool asn1)) | |
"if (rsa)\n" | |
" return(SSL_CTX_use_RSAPrivateKey_file(" | |
" (SSL_CTX *)ctx, path, " | |
" (asn1 ? SSL_FILETYPE_ASN1 : SSL_FILETYPE_PEM)));\n" | |
"else\n" | |
" return(SSL_CTX_use_PrivateKey_file(" | |
" (SSL_CTX *)ctx, path, " | |
" (asn1 ? SSL_FILETYPE_ASN1 : SSL_FILETYPE_PEM)));\n") | |
(ssl-unwrap-context obj) (##sys#expand-home-path pathname) | |
rsa? asn1?) | |
1) | |
(ssl-abort 'ssl-load-private-key! #f pathname rsa? asn1?))) | |
;; switch verification of peer on or off | |
(define (ssl-set-verify! obj v) | |
((foreign-lambda* | |
void | |
((c-pointer ctx) (bool verify)) | |
"SSL_CTX_set_verify((SSL_CTX *)ctx," | |
" (verify ? SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT" | |
" : SSL_VERIFY_NONE), NULL);\n") | |
(ssl-unwrap-context obj) v)) | |
;; load trusted root certificates into SSL context | |
(define (ssl-load-verify-root-certificates! obj pathname #!optional (dirname #f)) | |
(if pathname (##sys#check-string pathname)) | |
(if dirname (##sys#check-string dirname)) | |
(unless (eq? | |
((foreign-lambda | |
int "SSL_CTX_load_verify_locations" c-pointer c-string c-string) | |
(ssl-unwrap-context obj) | |
(if pathname (##sys#expand-home-path pathname) #f) | |
(if dirname (##sys#expand-home-path dirname) #f)) | |
1) | |
(ssl-abort 'ssl-load-verify-root-certificates! #f pathname dirname))) | |
;; load suggested root certificates into SSL context | |
(define (ssl-load-suggested-certificate-authorities! obj pathname) | |
(##sys#check-string pathname) | |
(cond | |
(((foreign-lambda c-pointer "SSL_load_client_CA_file" c-string) | |
(##sys#expand-home-path pathname)) | |
=> (cut | |
(foreign-lambda | |
void "SSL_CTX_set_client_CA_list" c-pointer c-pointer) | |
(ssl-unwrap-context obj) <>)) | |
(else | |
(ssl-abort 'ssl-load-suggested-certificate-authorities! #f pathname)))) | |
;; check whether the connection peer has presented a valid certificate | |
(define (ssl-peer-verified? p) | |
(ssl-port-startup p) | |
(let ((ssl (ssl-port->ssl p))) | |
(and ((foreign-lambda* | |
bool ((c-pointer ssl)) | |
"C_return(SSL_get_verify_result(ssl) == X509_V_OK);") | |
ssl) | |
((foreign-lambda* | |
bool ((c-pointer ssl)) | |
"X509 *crt = SSL_get_peer_certificate(ssl);\n" | |
"X509_free(crt);\n" | |
"C_return(crt != NULL);\n") | |
ssl)))) | |
;; obtain the subject name of the connection peer's certificate, if any | |
(define (ssl-peer-subject-name p) | |
(ssl-port-startup p) | |
((foreign-lambda* | |
c-string* ((c-pointer ssl)) | |
"X509 *crt = SSL_get_peer_certificate(ssl);\n" | |
"if (!crt) C_return(NULL);\n" | |
"char *name = X509_NAME_oneline(X509_get_subject_name(crt), NULL, -1);\n" | |
"X509_free(crt);\n" | |
"C_return(name);") | |
(ssl-port->ssl p))) | |
;; obtain the issuer name of the connection peer's certificate, if any | |
(define (ssl-peer-issuer-name p) | |
(ssl-port-startup p) | |
((foreign-lambda* | |
c-string* ((c-pointer ssl)) | |
"X509 *crt = SSL_get_peer_certificate(ssl);\n" | |
"if (!crt) C_return(NULL);\n" | |
"char *name = X509_NAME_oneline(X509_get_issuer_name(crt), NULL, -1);\n" | |
"X509_free(crt);\n" | |
"C_return(name);") | |
(ssl-port->ssl p))) | |
;; verify a signature, given a public key file | |
(define (ssl-signature-verify certfile signature) | |
((foreign-lambda* | |
c-string* ((c-string pathname) (c-string signature)) | |
"unsigned char *pad = RSA_PKCS1_PADDING;\n" | |
"EVP_PKEY *pkey = load_pubkey(NULL, pathname, str2fmt(\"PEM\"), 0, NULL, NULL, \"Public Key\");\n" | |
"RSA *rsa = EVP_PKEY_get1_RSA(pkey);\n" | |
"EVP_PKEY_free(pkey);\n" | |
"int keysize = RSA_size(rsa);\n" | |
"unsigned char *rsa_out = malloc(keysize);\n" | |
"int rsa_outlen = RSA_public_decrypt(strlen(signature), signature, rsa_out, rsa, pad);\n" | |
"C_return(rsa_out);\n") | |
(certfile signature))) | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment