check in some experimental X.509 parsing code

This commit is contained in:
leitner
2015-05-07 23:53:05 +00:00
parent ad390ee7ea
commit 2479167b37
11 changed files with 535 additions and 2 deletions

166
tinytls.h Normal file
View File

@@ -0,0 +1,166 @@
#ifndef _TINYTLS_H
#define _TINYTLS_H
#include <stdint.h>
#include <sys/types.h>
/* for struct string: */
#include "asn1.h"
typedef enum {
NONE,
FAIL, // protocol failure, refuse all operations
READ_CLIENTHELLO, // tls_accept called, trying to read client hello
WRITE_ALERTFAIL, // got something bad, write alert and fail
WRITE_SERVERHELLO, // got client hello, trying to write server hello
WRITE_CLIENTHELLO, // tls_connect called, trying to write client hello
READ_SERVERHELLO, // trying to read server hello
READ_CERT, // read server hello, trying to read cert
READ_SERVERHELLODONE, // read server hello + cert, trying to read server hello done
} tls_state;
enum { MAXCERT=4 };
struct ssl_context {
tls_state state;
char myrandom[28];
char theirrandom[28];
time_t timestamp; /* so we can age out old sessions from the session id cache */
const char* servername;
struct string session; // a cookie sent during the handshake, so if a client comes back later, we can save work
struct string mycert[MAXCERT]; // my own cert, maybe an intermediate cert, and a ca cert; sent during handshake
struct string theircert[MAXCERT];
struct string message; // the packet we are currently trying to read or write
size_t ofsinmessage;
char scratch[2048];
ssize_t (*_read)(uintptr_t handle,char* buf,size_t len);
ssize_t (*_write)(uintptr_t handle,const char* buf,size_t len);
int (*_close)(uintptr_t handle);
int (*readcert)(struct ssl_context* sc); // use sc->servername to read cert into sc->mycert
// return 0 for success, enum alerttype otherwise
uint16_t cipher,compressionmethod;
};
/* Put servername into ssl_context, set empty session. */
void init_tls_context_norandom(struct ssl_context* sc, const char* servername);
/* Put servername into ssl_context, and fill random bytes from
* /dev/urandom. Return 0 if OK, -1 if /dev/urandom failed */
int init_tls_context(struct ssl_context* sc, const char* servername);
/* Generate a client hello inside a handshake packet using the
* servername and session data from the context, return number of bytes
* written to dest. Call with dest=NULL to get needed buffer size. */
size_t fmt_tls_clienthello(char* dest, struct ssl_context* sc);
/* The response to a client hello consists of several packets:
1. server hello
2. certificate
[3. server key exchange for a DHE cipher suite]
4. server hello done */
/* Generate a server hello from a client hello that came in, return
* number of bytes written to dest.
* Call with dest=NULL to get needed buffer size.
* Returns (size_t)-1 if the client hello is not complete,
* (size_t)-2 if the client hello is invalid
* if the client helo is valid but has no common ciphers, write an alert
* and return length of alert (7) */
size_t fmt_tls_serverhello(char* dest,const char* clienthelo,size_t len,struct ssl_context* sc);
/*
* Allocate a buffer that can hold all the X.509 certificates plus 3
* bytes per certificate plus 12 bytes for the headers. Write the
* certificates to buf+12 using fmt_tls_handshake_cert. Then write
* the header to buf using fmt_tls_handshake_certs_header; give it the
* sum of the return values of fmt_tls_handshake_cert as len.
*/
size_t fmt_tls_handshake_cert(char* dest,const char* cert,size_t len);
size_t fmt_tls_handshake_certs_header(char* dest,size_t len_of_certs);
size_t fmt_tls_serverhellodone(char* dest);
size_t scan_tls_serverhello(const char* buf,size_t len,struct ssl_context* sc);
enum alertlevel {
WARNING=1,
FATAL=2
};
enum alerttype {
CLOSE_NOTIFY=0,
UNEXPECTED_MESSAGE=10,
BAD_RECORD_MAC=20,
DECRYPTION_FAILED=21,
RECORD_OVERFLOW=22,
DECOMPRESSION_FAILURE=30,
HANDSHAKE_FAILURE=40,
NO_CERT=41,
BAD_CERT=42,
UNSUPPORTED_CERT=43,
CERT_REVOKED=44,
CERT_EXPIRED=45,
CERT_UNKNOWN=46,
ILLEGAL_PARAMETER=47,
UNKNOWN_CA=48,
ACCESS_DENIED=49,
DECODE_ERROR=50,
DECRYPT_ERROR=51,
EXPORT_RESTRICTION=60,
PROTOCOL_VERSION=70,
INSUFFICIENT_SECURITY=71,
INTERNAL_ERROR=80,
USER_CANCELED=90,
NO_RENEGOTIATION=100,
UNSUPPORTED_EXT=110
};
/* Generate a TLS alert (only the alert!) */
size_t fmt_tls_alert(char* dest,enum alertlevel level,enum alerttype type);
/* Generate a TLS alert with outer header */
size_t fmt_tls_alert_pkt(char* dest,enum alertlevel level,enum alerttype type);
enum contenttype {
CHANGE_CIPHER_SPEC=20,
ALERT=21,
HANDSHAKE=22,
APPLICATION_DATA=23
};
size_t fmt_tls_packet(char* dest,enum contenttype ct, size_t len);
enum ciphers {
TLS_RSA_WITH_AES_256_CBC_SHA256=0x3d,
TLS_RSA_WITH_AES_256_CBC_SHA=0x35,
};
/* return the desirability of a cipher (number >= 0)
* or -1 if the cipher is not supported
* the higher the number, the less desirable is the cipher */
int tls_cipherprio(uint16_t cipher);
typedef enum {
OK=0,
IOFAIL=-1, // I/O error
WANTREAD=-2, // socket was non-blocking; wait for read event
WANTWRITE=-3, // socket was non-blocking; wait for write event
OOM=-4, // out of memory
PROTOCOLFAIL=-5, // received invalid packets
NEGOTIATIONFAIL=-6, // no common ciphers / compression methods
CRYPTOFAIL=-7, // cryptographic failure (weak key detected or so)
CERTFAIL=-8, // certificate validation failed
YOUSUCK=-42, // user-supplied callbacks violated protocol
} tls_error_code;
tls_error_code tls_connect(uintptr_t fd,struct ssl_context* sc);
tls_error_code tls_accept(uintptr_t fd,struct ssl_context* sc);
/* these are internal helpers */
tls_error_code tls_dowrite(uintptr_t fd,struct ssl_context* sc);
tls_error_code tls_doread(uintptr_t fd,struct ssl_context* sc);
tls_error_code tls_checkalert(struct ssl_context* sc);
#endif