diff --git a/sys/include/ape/auth.h b/sys/include/ape/auth.h new file mode 100644 index 000000000..ba68e30dc --- /dev/null +++ b/sys/include/ape/auth.h @@ -0,0 +1,155 @@ +#ifndef _PLAN9_SOURCE + This header file is an extension to ANSI/POSIX +#endif + +#ifndef __AUTH_H_ +#define __AUTH_H_ + +#pragma src "/sys/src/ape/lib/auth" +#pragma lib "/$M/lib/ape/libauth.a" + +#include +#include + +/* + * Interface for typical callers. + */ + +typedef struct AuthInfo AuthInfo; +typedef struct Chalstate Chalstate; +typedef struct Chapreply Chapreply; +typedef struct MSchapreply MSchapreply; +typedef struct UserPasswd UserPasswd; +typedef struct AuthRpc AuthRpc; + +enum +{ + MAXCHLEN= 256, /* max challenge length */ + MAXNAMELEN= 256, /* maximum name length */ + MD5LEN= 16, + + ARok = 0, /* rpc return values */ + ARdone, + ARerror, + ARneedkey, + ARbadkey, + ARwritenext, + ARtoosmall, + ARtoobig, + ARrpcfailure, + ARphase, + + AuthRpcMax = 4096, +}; + +struct AuthRpc +{ + int afd; + char ibuf[AuthRpcMax+1]; /* +1 for NUL in auth_rpc.c */ + char obuf[AuthRpcMax]; + char *arg; + uint narg; +}; + +struct AuthInfo +{ + char *cuid; /* caller id */ + char *suid; /* server id */ + char *cap; /* capability (only valid on server side) */ + int nsecret; /* length of secret */ + uchar *secret; /* secret */ +}; + +struct Chalstate +{ + char *user; + char chal[MAXCHLEN]; + int nchal; + void *resp; + int nresp; + +/* for implementation only */ + int afd; /* to factotum */ + AuthRpc *rpc; /* to factotum */ + char userbuf[MAXNAMELEN]; /* temp space if needed */ + int userinchal; /* user was sent to obtain challenge */ +}; + +struct Chapreply /* for protocol "chap" */ +{ + uchar id; + char resp[MD5LEN]; +}; + +struct MSchapreply /* for protocol "mschap" */ +{ + char LMresp[24]; /* Lan Manager response */ + char NTresp[24]; /* NT response */ +}; + +struct UserPasswd +{ + char *user; + char *passwd; +}; + +extern int newns(char*, char*); +extern int addns(char*, char*); + +extern int noworld(char*); +extern int amount(int, char*, int, char*); + +/* these two may get generalized away -rsc */ +extern int login(char*, char*, char*); +extern int httpauth(char*, char*); + +typedef struct Attr Attr; +enum { + AttrNameval, /* name=val -- when matching, must have name=val */ + AttrQuery, /* name? -- when matching, must be present */ + AttrDefault, /* name:=val -- when matching, if present must match INTERNAL */ +}; +struct Attr +{ + int type; + Attr *next; + char *name; + char *val; +}; + +typedef int AuthGetkey(char*); + +int _attrfmt(Fmt*); +Attr *_copyattr(Attr*); +Attr *_delattr(Attr*, char*); +Attr *_findattr(Attr*, char*); +void _freeattr(Attr*); +Attr *_mkattr(int, char*, char*, Attr*); +Attr *_parseattr(char*); +char *_strfindattr(Attr*, char*); +#pragma varargck type "A" Attr* + +extern AuthInfo* fauth_proxy(int, AuthRpc *rpc, AuthGetkey *getkey, char *params); +extern AuthInfo* auth_proxy(int fd, AuthGetkey *getkey, char *fmt, ...); +extern int auth_getkey(char*); +extern int (*amount_getkey)(char*); +extern void auth_freeAI(AuthInfo *ai); +extern int auth_chuid(AuthInfo *ai, char *ns); +extern Chalstate *auth_challenge(char*, ...); +extern AuthInfo* auth_response(Chalstate*); +extern int auth_respond(void*, uint, char*, uint, void*, uint, AuthGetkey *getkey, char*, ...); +extern void auth_freechal(Chalstate*); +extern AuthInfo* auth_userpasswd(char *user, char *passwd); +extern UserPasswd* auth_getuserpasswd(AuthGetkey *getkey, char*, ...); +extern AuthInfo* auth_getinfo(AuthRpc *rpc); +extern AuthRpc* auth_allocrpc(int afd); +extern Attr* auth_attr(AuthRpc *rpc); +extern void auth_freerpc(AuthRpc *rpc); +extern uint auth_rpc(AuthRpc *rpc, char *verb, void *a, int n); +extern int auth_wep(char*, char*, ...); +#pragma varargck argpos auth_proxy 3 +#pragma varargck argpos auth_challenge 1 +#pragma varargck argpos auth_respond 8 +#pragma varargck argpos auth_getuserpasswd 2 + +#endif diff --git a/sys/include/ape/bio.h b/sys/include/ape/bio.h new file mode 100644 index 000000000..ffceaae84 --- /dev/null +++ b/sys/include/ape/bio.h @@ -0,0 +1,89 @@ +#ifndef _PLAN9_SOURCE + This header file is an extension to ANSI/POSIX +#endif + +#ifndef __BIO_H_ +#define __BIO_H_ +#pragma src "/sys/src/libbio" +#pragma lib "/$M/lib/ape/libbio.a" + +#include + +typedef struct Biobuf Biobuf; +typedef struct Biobufhdr Biobufhdr; + +enum +{ + Bsize = 8*1024, + Bungetsize = UTFmax+1, /* space for ungetc */ + Bmagic = 0x314159, + Beof = -1, + Bbad = -2, + + Binactive = 0, /* states */ + Bractive, + Bwactive, + Bracteof, +}; + +struct Biobufhdr +{ + int icount; /* neg num of bytes at eob */ + int ocount; /* num of bytes at bob */ + int rdline; /* num of bytes after rdline */ + int runesize; /* num of bytes of last getrune */ + int state; /* r/w/inactive */ + int fid; /* open file */ + int flag; /* magic if malloc'ed */ + vlong offset; /* offset of buffer in file */ + int bsize; /* size of buffer */ + uchar* bbuf; /* pointer to beginning of buffer */ + uchar* ebuf; /* pointer to end of buffer */ + uchar* gbuf; /* pointer to good data in buf */ + void (*errorf)(char *); /* called on error if not nil */ +}; + +struct Biobuf +{ + Biobufhdr; + uchar b[Bungetsize+Bsize]; +}; + +/* Dregs, redefined as functions for backwards compatibility */ +#define BGETC(bp) Bgetc(bp) +#define BPUTC(bp,c) Bputc(bp,c) +#define BOFFSET(bp) Boffset(bp) +#define BLINELEN(bp) Blinelen(bp) +#define BFILDES(bp) Bfildes(bp) + +int Bbuffered(Biobufhdr*); +int Bfildes(Biobufhdr*); +int Bflush(Biobufhdr*); +int Bgetc(Biobufhdr*); +int Bgetd(Biobufhdr*, double*); +long Bgetrune(Biobufhdr*); +int Binit(Biobuf*, int, int); +int Binits(Biobufhdr*, int, int, uchar*, int); +int Blinelen(Biobufhdr*); +vlong Boffset(Biobufhdr*); +Biobuf* Bopen(char*, int); +Biobuf* Bfdopen(int, int); +int Bprint(Biobufhdr*, char*, ...); +int Bvprint(Biobufhdr*, char*, va_list); +int Bputc(Biobufhdr*, int); +int Bputrune(Biobufhdr*, long); +void* Brdline(Biobufhdr*, int); +char* Brdstr(Biobufhdr*, int, int); +long Bread(Biobufhdr*, void*, long); +vlong Bseek(Biobufhdr*, vlong, int); +int Bterm(Biobufhdr*); +int Bungetc(Biobufhdr*); +int Bungetrune(Biobufhdr*); +long Bwrite(Biobufhdr*, void*, long); +void Blethal(Biobufhdr*, void(*)(char*)); +void Berror(Biobufhdr*, char*, ...); + +#pragma varargck argpos Bprint 2 +#pragma varargck argpos Berror 2 + +#endif diff --git a/sys/include/ape/libsec.h b/sys/include/ape/libsec.h new file mode 100644 index 000000000..37a59c078 --- /dev/null +++ b/sys/include/ape/libsec.h @@ -0,0 +1,584 @@ +#ifndef _PLAN9_SOURCE + This header file is an extension to ANSI/POSIX +#endif + +#ifndef __LIBSEC_H_ +#define __LIBSEC_H_ + +#pragma src "/sys/src/ape/lib/sec" +#pragma lib "/$M/lib/ape/libsec.a" + +#include + +#ifndef _MPINT +typedef struct mpint mpint; +#endif + +/* + * AES definitions + */ + +enum +{ + AESbsize= 16, + AESmaxkey= 32, + AESmaxrounds= 14 +}; + +typedef struct AESstate AESstate; +struct AESstate +{ + ulong setup; + int rounds; + int keybytes; + uchar key[AESmaxkey]; /* unexpanded key */ + ulong ekey[4*(AESmaxrounds + 1)]; /* encryption key */ + ulong dkey[4*(AESmaxrounds + 1)]; /* decryption key */ + uchar ivec[AESbsize]; /* initialization vector */ + uchar mackey[3 * AESbsize]; /* 3 XCBC mac 96 keys */ +}; + +/* block ciphers */ +void aes_encrypt(ulong rk[], int Nr, uchar pt[16], uchar ct[16]); +void aes_decrypt(ulong rk[], int Nr, uchar ct[16], uchar pt[16]); + +void setupAESstate(AESstate *s, uchar key[], int keybytes, uchar *ivec); +void aesCBCencrypt(uchar *p, int len, AESstate *s); +void aesCBCdecrypt(uchar *p, int len, AESstate *s); + +void setupAESXCBCstate(AESstate *s); +uchar* aesXCBCmac(uchar *p, int len, AESstate *s); + +typedef struct AESGCMstate AESGCMstate; +struct AESGCMstate +{ + AESstate; + + ulong H[4]; + ulong M[16][256][4]; +}; + +void setupAESGCMstate(AESGCMstate *s, uchar *key, int keylen, uchar *iv, int ivlen); +void aesgcm_setiv(AESGCMstate *s, uchar *iv, int ivlen); +void aesgcm_encrypt(uchar *dat, ulong ndat, uchar *aad, ulong naad, uchar tag[16], AESGCMstate *s); +int aesgcm_decrypt(uchar *dat, ulong ndat, uchar *aad, ulong naad, uchar tag[16], AESGCMstate *s); + +/* + * Blowfish Definitions + */ + +enum +{ + BFbsize = 8, + BFrounds= 16 +}; + +/* 16-round Blowfish */ +typedef struct BFstate BFstate; +struct BFstate +{ + ulong setup; + + uchar key[56]; + uchar ivec[8]; + + u32int pbox[BFrounds+2]; + u32int sbox[1024]; +}; + +void setupBFstate(BFstate *s, uchar key[], int keybytes, uchar *ivec); +void bfCBCencrypt(uchar*, int, BFstate*); +void bfCBCdecrypt(uchar*, int, BFstate*); +void bfECBencrypt(uchar*, int, BFstate*); +void bfECBdecrypt(uchar*, int, BFstate*); + +/* + * Chacha definitions + */ + +enum +{ + ChachaBsize= 64, + ChachaKeylen= 256/8, + ChachaIVlen= 96/8, +}; + +typedef struct Chachastate Chachastate; +struct Chachastate +{ + union{ + u32int input[16]; + struct { + u32int constant[4]; + u32int key[8]; + u32int counter; + u32int iv[3]; + }; + }; + int rounds; + int ivwords; +}; + +void setupChachastate(Chachastate*, uchar*, ulong, uchar*, ulong, int); +void chacha_setiv(Chachastate *, uchar*); +void chacha_setblock(Chachastate*, u64int); +void chacha_encrypt(uchar*, ulong, Chachastate*); +void chacha_encrypt2(uchar*, uchar*, ulong, Chachastate*); + +void ccpoly_encrypt(uchar *dat, ulong ndat, uchar *aad, ulong naad, uchar tag[16], Chachastate *cs); +int ccpoly_decrypt(uchar *dat, ulong ndat, uchar *aad, ulong naad, uchar tag[16], Chachastate *cs); + +/* + * Salsa definitions + */ +enum +{ + SalsaBsize= 64, + SalsaKeylen= 256/8, + SalsaIVlen= 64/8, + XSalsaIVlen= 192/8, +}; + +typedef struct Salsastate Salsastate; +struct Salsastate +{ + u32int input[16]; + u32int key[8]; + int rounds; + int ivwords; +}; + +void setupSalsastate(Salsastate*, uchar*, ulong, uchar*, ulong, int); +void salsa_setiv(Salsastate*, uchar*); +void salsa_setblock(Salsastate*, u64int); +void salsa_encrypt(uchar*, ulong, Salsastate*); +void salsa_encrypt2(uchar*, uchar*, ulong, Salsastate*); + +void hsalsa(uchar h[32], uchar *key, ulong keylen, uchar nonce[16], int rounds); + +/* + * DES definitions + */ + +enum +{ + DESbsize= 8 +}; + +/* single des */ +typedef struct DESstate DESstate; +struct DESstate +{ + ulong setup; + uchar key[8]; /* unexpanded key */ + ulong expanded[32]; /* expanded key */ + uchar ivec[8]; /* initialization vector */ +}; + +void setupDESstate(DESstate *s, uchar key[8], uchar *ivec); +void des_key_setup(uchar[8], ulong[32]); +void block_cipher(ulong*, uchar*, int); +void desCBCencrypt(uchar*, int, DESstate*); +void desCBCdecrypt(uchar*, int, DESstate*); +void desECBencrypt(uchar*, int, DESstate*); +void desECBdecrypt(uchar*, int, DESstate*); + +/* for backward compatibility with 7-byte DES key format */ +void des56to64(uchar *k56, uchar *k64); +void des64to56(uchar *k64, uchar *k56); +void key_setup(uchar[7], ulong[32]); + +/* triple des encrypt/decrypt orderings */ +enum { + DES3E= 0, + DES3D= 1, + DES3EEE= 0, + DES3EDE= 2, + DES3DED= 5, + DES3DDD= 7 +}; + +typedef struct DES3state DES3state; +struct DES3state +{ + ulong setup; + uchar key[3][8]; /* unexpanded key */ + ulong expanded[3][32]; /* expanded key */ + uchar ivec[8]; /* initialization vector */ +}; + +void setupDES3state(DES3state *s, uchar key[3][8], uchar *ivec); +void triple_block_cipher(ulong keys[3][32], uchar*, int); +void des3CBCencrypt(uchar*, int, DES3state*); +void des3CBCdecrypt(uchar*, int, DES3state*); +void des3ECBencrypt(uchar*, int, DES3state*); +void des3ECBdecrypt(uchar*, int, DES3state*); + +/* + * digests + */ + +enum +{ + SHA1dlen= 20, /* SHA digest length */ + SHA2_224dlen= 28, /* SHA-224 digest length */ + SHA2_256dlen= 32, /* SHA-256 digest length */ + SHA2_384dlen= 48, /* SHA-384 digest length */ + SHA2_512dlen= 64, /* SHA-512 digest length */ + MD4dlen= 16, /* MD4 digest length */ + MD5dlen= 16, /* MD5 digest length */ + Poly1305dlen= 16, /* Poly1305 digest length */ + + Hmacblksz = 64, /* in bytes; from rfc2104 */ +}; + +typedef struct DigestState DigestState; +struct DigestState +{ + uvlong len; + union { + u32int state[16]; + u64int bstate[8]; + }; + uchar buf[256]; + int blen; + char malloced; + char seeded; +}; +typedef struct DigestState SHAstate; /* obsolete name */ +typedef struct DigestState SHA1state; +typedef struct DigestState SHA2_224state; +typedef struct DigestState SHA2_256state; +typedef struct DigestState SHA2_384state; +typedef struct DigestState SHA2_512state; +typedef struct DigestState MD5state; +typedef struct DigestState MD4state; + +DigestState* md4(uchar*, ulong, uchar*, DigestState*); +DigestState* md5(uchar*, ulong, uchar*, DigestState*); +DigestState* sha1(uchar*, ulong, uchar*, DigestState*); +DigestState* sha2_224(uchar*, ulong, uchar*, DigestState*); +DigestState* sha2_256(uchar*, ulong, uchar*, DigestState*); +DigestState* sha2_384(uchar*, ulong, uchar*, DigestState*); +DigestState* sha2_512(uchar*, ulong, uchar*, DigestState*); +DigestState* hmac_x(uchar *p, ulong len, uchar *key, ulong klen, + uchar *digest, DigestState *s, + DigestState*(*x)(uchar*, ulong, uchar*, DigestState*), + int xlen); +DigestState* hmac_md5(uchar*, ulong, uchar*, ulong, uchar*, DigestState*); +DigestState* hmac_sha1(uchar*, ulong, uchar*, ulong, uchar*, DigestState*); +DigestState* hmac_sha2_224(uchar*, ulong, uchar*, ulong, uchar*, DigestState*); +DigestState* hmac_sha2_256(uchar*, ulong, uchar*, ulong, uchar*, DigestState*); +DigestState* hmac_sha2_384(uchar*, ulong, uchar*, ulong, uchar*, DigestState*); +DigestState* hmac_sha2_512(uchar*, ulong, uchar*, ulong, uchar*, DigestState*); +char* md5pickle(MD5state*); +MD5state* md5unpickle(char*); +char* sha1pickle(SHA1state*); +SHA1state* sha1unpickle(char*); + +DigestState* poly1305(uchar*, ulong, uchar*, ulong, uchar*, DigestState*); + +/* + * random number generation + */ +void genrandom(uchar *buf, int nbytes); +void prng(uchar *buf, int nbytes); +ulong fastrand(void); +ulong nfastrand(ulong); + +/* + * primes + */ +void genprime(mpint *p, int n, int accuracy); /* generate n-bit probable prime */ +void gensafeprime(mpint *p, mpint *alpha, int n, int accuracy); /* prime & generator */ +void genstrongprime(mpint *p, int n, int accuracy); /* generate n-bit strong prime */ +void DSAprimes(mpint *q, mpint *p, uchar seed[SHA1dlen]); +int probably_prime(mpint *n, int nrep); /* miller-rabin test */ +int smallprimetest(mpint *p); /* returns -1 if not prime, 0 otherwise */ + +/* + * rc4 + */ +typedef struct RC4state RC4state; +struct RC4state +{ + uchar state[256]; + uchar x; + uchar y; +}; + +void setupRC4state(RC4state*, uchar*, int); +void rc4(RC4state*, uchar*, int); +void rc4skip(RC4state*, int); +void rc4back(RC4state*, int); + +/* + * rsa + */ +typedef struct RSApub RSApub; +typedef struct RSApriv RSApriv; +typedef struct PEMChain PEMChain; + +/* public/encryption key */ +struct RSApub +{ + mpint *n; /* modulus */ + mpint *ek; /* exp (encryption key) */ +}; + +/* private/decryption key */ +struct RSApriv +{ + RSApub pub; + + mpint *dk; /* exp (decryption key) */ + + /* precomputed values to help with chinese remainder theorem calc */ + mpint *p; + mpint *q; + mpint *kp; /* dk mod p-1 */ + mpint *kq; /* dk mod q-1 */ + mpint *c2; /* (inv p) mod q */ +}; + +struct PEMChain{ + PEMChain*next; + uchar *pem; + int pemlen; +}; + +RSApriv* rsagen(int nlen, int elen, int rounds); +RSApriv* rsafill(mpint *n, mpint *e, mpint *d, mpint *p, mpint *q); +mpint* rsaencrypt(RSApub *k, mpint *in, mpint *out); +mpint* rsadecrypt(RSApriv *k, mpint *in, mpint *out); +RSApub* rsapuballoc(void); +void rsapubfree(RSApub*); +RSApriv* rsaprivalloc(void); +void rsaprivfree(RSApriv*); +RSApub* rsaprivtopub(RSApriv*); +RSApub* X509toRSApub(uchar*, int, char*, int); +RSApriv* asn1toRSApriv(uchar*, int); +void asn1dump(uchar *der, int len); +uchar* decodePEM(char *s, char *type, int *len, char **new_s); +PEMChain* decodepemchain(char *s, char *type); +uchar* X509rsagen(RSApriv *priv, char *subj, ulong valid[2], int *certlen); +uchar* X509rsareq(RSApriv *priv, char *subj, int *certlen); +char* X509rsaverifydigest(uchar *sig, int siglen, uchar *edigest, int edigestlen, RSApub *pk); +char* X509rsaverify(uchar *cert, int ncert, RSApub *pk); + +void X509dump(uchar *cert, int ncert); + +/* + * elgamal + */ +typedef struct EGpub EGpub; +typedef struct EGpriv EGpriv; +typedef struct EGsig EGsig; + +/* public/encryption key */ +struct EGpub +{ + mpint *p; /* modulus */ + mpint *alpha; /* generator */ + mpint *key; /* (encryption key) alpha**secret mod p */ +}; + +/* private/decryption key */ +struct EGpriv +{ + EGpub pub; + mpint *secret; /* (decryption key) */ +}; + +/* signature */ +struct EGsig +{ + mpint *r, *s; +}; + +EGpriv* eggen(int nlen, int rounds); +mpint* egencrypt(EGpub *k, mpint *in, mpint *out); /* deprecated */ +mpint* egdecrypt(EGpriv *k, mpint *in, mpint *out); +EGsig* egsign(EGpriv *k, mpint *m); +int egverify(EGpub *k, EGsig *sig, mpint *m); +EGpub* egpuballoc(void); +void egpubfree(EGpub*); +EGpriv* egprivalloc(void); +void egprivfree(EGpriv*); +EGsig* egsigalloc(void); +void egsigfree(EGsig*); +EGpub* egprivtopub(EGpriv*); + +/* + * dsa + */ +typedef struct DSApub DSApub; +typedef struct DSApriv DSApriv; +typedef struct DSAsig DSAsig; + +/* public/encryption key */ +struct DSApub +{ + mpint *p; /* modulus */ + mpint *q; /* group order, q divides p-1 */ + mpint *alpha; /* group generator */ + mpint *key; /* (encryption key) alpha**secret mod p */ +}; + +/* private/decryption key */ +struct DSApriv +{ + DSApub pub; + mpint *secret; /* (decryption key) */ +}; + +/* signature */ +struct DSAsig +{ + mpint *r, *s; +}; + +DSApriv* dsagen(DSApub *opub); /* opub not checked for consistency! */ +DSAsig* dsasign(DSApriv *k, mpint *m); +int dsaverify(DSApub *k, DSAsig *sig, mpint *m); +DSApub* dsapuballoc(void); +void dsapubfree(DSApub*); +DSApriv* dsaprivalloc(void); +void dsaprivfree(DSApriv*); +DSAsig* dsasigalloc(void); +void dsasigfree(DSAsig*); +DSApub* dsaprivtopub(DSApriv*); +DSApriv* asn1toDSApriv(uchar*, int); + +/* + * TLS + */ +typedef struct Thumbprint{ + struct Thumbprint *next; + uchar sha1[SHA1dlen]; +} Thumbprint; + +typedef struct TLSconn{ + char dir[40]; /* connection directory */ + uchar *cert; /* certificate (local on input, remote on output) */ + uchar *sessionID; + uchar *psk; + int certlen; + int sessionIDlen; + int psklen; + int (*trace)(char*fmt, ...); + PEMChain*chain; /* optional extra certificate evidence for servers to present */ + char *sessionType; + uchar *sessionKey; + int sessionKeylen; + char *sessionConst; + char *serverName; + char *pskID; +} TLSconn; + +/* tlshand.c */ +int tlsClient(int fd, TLSconn *c); +int tlsServer(int fd, TLSconn *c); + +/* thumb.c */ +Thumbprint* initThumbprints(char *ok, char *crl); +void freeThumbprints(Thumbprint *ok); +int okThumbprint(uchar *sha1, Thumbprint *ok); + +/* readcert.c */ +uchar *readcert(char *filename, int *pcertlen); +PEMChain*readcertchain(char *filename); + +/* aes_xts.c */ +int aes_xts_encrypt(ulong tweak[], ulong ecb[], vlong sectorNumber, uchar *input, uchar *output, ulong len) ; +int aes_xts_decrypt(ulong tweak[], ulong ecb[], vlong sectorNumber, uchar *input, uchar *output, ulong len); + +typedef struct ECpoint{ + int inf; + mpint *x; + mpint *y; +} ECpoint; + +typedef ECpoint ECpub; +typedef struct ECpriv{ + ECpoint; + mpint *d; +} ECpriv; + +typedef struct ECdomain{ + mpint *p; + mpint *a; + mpint *b; + ECpoint G; + mpint *n; + mpint *h; +} ECdomain; + +void ecdominit(ECdomain *, void (*init)(mpint *p, mpint *a, mpint *b, mpint *x, mpint *y, mpint *n, mpint *h)); +void ecdomfree(ECdomain *); + +void ecassign(ECdomain *, ECpoint *old, ECpoint *new); +void ecadd(ECdomain *, ECpoint *a, ECpoint *b, ECpoint *s); +void ecmul(ECdomain *, ECpoint *a, mpint *k, ECpoint *s); +ECpoint* strtoec(ECdomain *, char *, char **, ECpoint *); +ECpriv* ecgen(ECdomain *, ECpriv*); +int ecverify(ECdomain *, ECpoint *); +int ecpubverify(ECdomain *, ECpub *); +void ecdsasign(ECdomain *, ECpriv *, uchar *, int, mpint *, mpint *); +int ecdsaverify(ECdomain *, ECpub *, uchar *, int, mpint *, mpint *); +void base58enc(uchar *, char *, int); +int base58dec(char *, uchar *, int); + +ECpub* ecdecodepub(ECdomain *dom, uchar *, int); +int ecencodepub(ECdomain *dom, ECpub *, uchar *, int); +void ecpubfree(ECpub *); + +ECpub* X509toECpub(uchar *cert, int ncert, ECdomain *dom); +char* X509ecdsaverifydigest(uchar *sig, int siglen, uchar *edigest, int edigestlen, ECdomain *dom, ECpub *pub); +char* X509ecdsaverify(uchar *sig, int siglen, ECdomain *dom, ECpub *pub); + +/* curves */ +void secp256r1(mpint *p, mpint *a, mpint *b, mpint *x, mpint *y, mpint *n, mpint *h); +void secp256k1(mpint *p, mpint *a, mpint *b, mpint *x, mpint *y, mpint *n, mpint *h); + +DigestState* ripemd160(uchar *, ulong, uchar *, DigestState *); + +/* + * Diffie-Hellman key exchange + */ + +typedef struct DHstate DHstate; +struct DHstate +{ + mpint *g; /* base g */ + mpint *p; /* large prime */ + mpint *q; /* subgroup prime */ + mpint *x; /* random secret */ + mpint *y; /* public key y = g**x % p */ +}; + +/* generate new public key: y = g**x % p */ +mpint* dh_new(DHstate *dh, mpint *p, mpint *q, mpint *g); + +/* calculate shared key: k = y**x % p */ +mpint* dh_finish(DHstate *dh, mpint *y); + +/* Curve25519 elliptic curve, public key function */ +void curve25519(uchar mypublic[32], uchar secret[32], uchar basepoint[32]); + +/* Curve25519 diffie hellman */ +void curve25519_dh_new(uchar x[32], uchar y[32]); +void curve25519_dh_finish(uchar x[32], uchar y[32], uchar z[32]); + +/* password-based key derivation function 2 (rfc2898) */ +void pbkdf2_x(uchar *p, ulong plen, uchar *s, ulong slen, ulong rounds, uchar *d, ulong dlen, + DigestState* (*x)(uchar*, ulong, uchar*, ulong, uchar*, DigestState*), int xlen); + +/* hmac-based key derivation function (rfc5869) */ +void hkdf_x(uchar *salt, ulong nsalt, uchar *info, ulong ninfo, uchar *key, ulong nkey, uchar *d, ulong dlen, + DigestState* (*x)(uchar*, ulong, uchar*, ulong, uchar*, DigestState*), int xlen); + +/* timing safe memcmp() */ +int tsmemcmp(void*, void*, ulong); + +#endif diff --git a/sys/include/ape/mp.h b/sys/include/ape/mp.h new file mode 100644 index 000000000..e18a70d92 --- /dev/null +++ b/sys/include/ape/mp.h @@ -0,0 +1,196 @@ +#ifndef _PLAN9_SOURCE + This header file is an extension to ANSI/POSIX +#endif + +#ifndef __LIBMP_H_ +#define __LIBMP_H_ + +#pragma src "/sys/src/ape/lib/mp" +#pragma lib "/$M/lib/ape/libmp.a" + +#include +#include + +typedef unsigned int mpdigit; /* from /$objtype/include/u.h */ + +#define _MPINT 1 + +/* + * the code assumes mpdigit to be at least an int + * mpdigit must be an atomic type. mpdigit is defined + * in the architecture specific u.h + */ +typedef struct mpint mpint; + +struct mpint +{ + int sign; /* +1 or -1 */ + int size; /* allocated digits */ + int top; /* significant digits */ + mpdigit *p; + char flags; +}; + +enum +{ + MPstatic= 0x01, /* static constant */ + MPnorm= 0x02, /* normalization status */ + MPtimesafe= 0x04, /* request time invariant computation */ + MPfield= 0x08, /* this mpint is a field modulus */ + + Dbytes= sizeof(mpdigit), /* bytes per digit */ + Dbits= Dbytes*8 /* bits per digit */ +}; + +/* allocation */ +void mpsetminbits(int n); /* newly created mpint's get at least n bits */ +mpint* mpnew(int n); /* create a new mpint with at least n bits */ +void mpfree(mpint *b); +void mpbits(mpint *b, int n); /* ensure that b has at least n bits */ +mpint* mpnorm(mpint *b); /* dump leading zeros */ +mpint* mpcopy(mpint *b); +void mpassign(mpint *old, mpint *new); + +/* random bits */ +mpint* mprand(int bits, void (*gen)(uchar*, int), mpint *b); +/* return uniform random [0..n-1] */ +mpint* mpnrand(mpint *n, void (*gen)(uchar*, int), mpint *b); + +/* conversion */ +mpint* strtomp(char*, char**, int, mpint*); /* ascii */ +int mpfmt(Fmt*); +char* mptoa(mpint*, int, char*, int); +mpint* letomp(uchar*, uint, mpint*); /* byte array, little-endian */ +int mptole(mpint*, uchar*, uint, uchar**); +void mptolel(mpint *b, uchar *p, int n); +mpint* betomp(uchar*, uint, mpint*); /* byte array, big-endian */ +int mptobe(mpint*, uchar*, uint, uchar**); +void mptober(mpint *b, uchar *p, int n); +uint mptoui(mpint*); /* unsigned int */ +mpint* uitomp(uint, mpint*); +int mptoi(mpint*); /* int */ +mpint* itomp(int, mpint*); +uvlong mptouv(mpint*); /* unsigned vlong */ +mpint* uvtomp(uvlong, mpint*); +vlong mptov(mpint*); /* vlong */ +mpint* vtomp(vlong, mpint*); + +/* divide 2 digits by one */ +void mpdigdiv(mpdigit *dividend, mpdigit divisor, mpdigit *quotient); + +/* in the following, the result mpint may be */ +/* the same as one of the inputs. */ +void mpadd(mpint *b1, mpint *b2, mpint *sum); /* sum = b1+b2 */ +void mpsub(mpint *b1, mpint *b2, mpint *diff); /* diff = b1-b2 */ +void mpleft(mpint *b, int shift, mpint *res); /* res = b<>shift */ +void mpmul(mpint *b1, mpint *b2, mpint *prod); /* prod = b1*b2 */ +void mpexp(mpint *b, mpint *e, mpint *m, mpint *res); /* res = b**e mod m */ +void mpmod(mpint *b, mpint *m, mpint *remainder); /* remainder = b mod m */ + +/* logical operations */ +void mpand(mpint *b1, mpint *b2, mpint *res); +void mpbic(mpint *b1, mpint *b2, mpint *res); +void mpor(mpint *b1, mpint *b2, mpint *res); +void mpnot(mpint *b, mpint *res); +void mpxor(mpint *b1, mpint *b2, mpint *res); +void mptrunc(mpint *b, int n, mpint *res); +void mpxtend(mpint *b, int n, mpint *res); + +/* modular arithmetic, time invariant when 0≤b1≤m-1 and 0≤b2≤m-1 */ +void mpmodadd(mpint *b1, mpint *b2, mpint *m, mpint *sum); /* sum = b1+b2 % m */ +void mpmodsub(mpint *b1, mpint *b2, mpint *m, mpint *diff); /* diff = b1-b2 % m */ +void mpmodmul(mpint *b1, mpint *b2, mpint *m, mpint *prod); /* prod = b1*b2 % m */ + +/* quotient = dividend/divisor, remainder = dividend % divisor */ +void mpdiv(mpint *dividend, mpint *divisor, mpint *quotient, mpint *remainder); + +/* return neg, 0, pos as b1-b2 is neg, 0, pos */ +int mpcmp(mpint *b1, mpint *b2); + +/* res = s != 0 ? b1 : b2 */ +void mpsel(int s, mpint *b1, mpint *b2, mpint *res); + +/* extended gcd return d, x, and y, s.t. d = gcd(a,b) and ax+by = d */ +void mpextendedgcd(mpint *a, mpint *b, mpint *d, mpint *x, mpint *y); + +/* res = b**-1 mod m */ +void mpinvert(mpint *b, mpint *m, mpint *res); + +/* bit counting */ +int mpsignif(mpint*); /* number of sigificant bits in mantissa */ +int mplowbits0(mpint*); /* k, where n = 2**k * q for odd q */ + +/* well known constants */ +extern mpint *mpzero, *mpone, *mptwo; + +/* sum[0:alen] = a[0:alen-1] + b[0:blen-1] */ +/* prereq: alen >= blen, sum has room for alen+1 digits */ +void mpvecadd(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *sum); + +/* diff[0:alen-1] = a[0:alen-1] - b[0:blen-1] */ +/* prereq: alen >= blen, diff has room for alen digits */ +void mpvecsub(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *diff); + +/* p[0:n] += m * b[0:n-1] */ +/* prereq: p has room for n+1 digits */ +void mpvecdigmuladd(mpdigit *b, int n, mpdigit m, mpdigit *p); + +/* p[0:n] -= m * b[0:n-1] */ +/* prereq: p has room for n+1 digits */ +int mpvecdigmulsub(mpdigit *b, int n, mpdigit m, mpdigit *p); + +/* p[0:alen+blen-1] = a[0:alen-1] * b[0:blen-1] */ +/* prereq: alen >= blen, p has room for m*n digits */ +void mpvecmul(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *p); +void mpvectsmul(mpdigit *a, int alen, mpdigit *b, int blen, mpdigit *p); + +/* sign of a - b or zero if the same */ +int mpveccmp(mpdigit *a, int alen, mpdigit *b, int blen); +int mpvectscmp(mpdigit *a, int alen, mpdigit *b, int blen); + +/* divide the 2 digit dividend by the one digit divisor and stick in quotient */ +/* we assume that the result is one digit - overflow is all 1's */ +void mpdigdiv(mpdigit *dividend, mpdigit divisor, mpdigit *quotient); + +/* playing with magnitudes */ +int mpmagcmp(mpint *b1, mpint *b2); +void mpmagadd(mpint *b1, mpint *b2, mpint *sum); /* sum = b1+b2 */ +void mpmagsub(mpint *b1, mpint *b2, mpint *sum); /* sum = b1+b2 */ + +/* chinese remainder theorem */ +typedef struct CRTpre CRTpre; /* precomputed values for converting */ + /* twixt residues and mpint */ +typedef struct CRTres CRTres; /* residue form of an mpint */ + +#pragma incomplete CRTpre + +struct CRTres +{ + int n; /* number of residues */ + mpint *r[1]; /* residues */ +}; + +CRTpre* crtpre(int, mpint**); /* precompute conversion values */ +CRTres* crtin(CRTpre*, mpint*); /* convert mpint to residues */ +void crtout(CRTpre*, CRTres*, mpint*); /* convert residues to mpint */ +void crtprefree(CRTpre*); +void crtresfree(CRTres*); + +/* fast field arithmetic */ +typedef struct Mfield Mfield; + +struct Mfield +{ + mpint; + int (*reduce)(Mfield*, mpint*, mpint*); +}; + +mpint *mpfield(mpint*); + +Mfield *gmfield(mpint*); +Mfield *cnfield(mpint*); + +#pragma varargck type "B" mpint* + +#endif diff --git a/sys/include/ape/u.h b/sys/include/ape/u.h index 4ce766194..310379c08 100644 --- a/sys/include/ape/u.h +++ b/sys/include/ape/u.h @@ -16,4 +16,9 @@ typedef uint Rune; typedef union FPdbleword FPdbleword; typedef char* p9va_list; +typedef uchar u8int; +typedef ushort u16int; +typedef ulong u32int; +typedef uvlong u64int; + #endif diff --git a/sys/src/ape/lib/9/ctime.c b/sys/src/ape/lib/9/ctime.c new file mode 100644 index 000000000..d8cdcef4c --- /dev/null +++ b/sys/src/ape/lib/9/ctime.c @@ -0,0 +1,22 @@ +#include "libc.h" + +#undef gmtime + +Tm* +_gmtime(time_t t) +{ + static Tm r; + struct tm *p; + + p = gmtime(&t); + r.sec = p->tm_sec; + r.min = p->tm_min; + r.hour = p->tm_hour; + r.mday = p->tm_mday; + r.mon = p->tm_mon; + r.year = p->tm_year; + r.wday = p->tm_wday; + r.yday = p->tm_yday; + strcpy(r.zone, "GMT"); + return &r; +} diff --git a/sys/src/ape/lib/9/libc.h b/sys/src/ape/lib/9/libc.h index 6ec1580c2..de885a964 100644 --- a/sys/src/ape/lib/9/libc.h +++ b/sys/src/ape/lib/9/libc.h @@ -1,6 +1,11 @@ #define _LOCK_EXTENSION #define _QLOCK_EXTENSION #define _BSD_EXTENSION + +#ifdef _NET_EXTENSION +#include +#endif + #include #include #include @@ -15,6 +20,7 @@ #include #include #include +#include #define nelem(x) (sizeof(x)/sizeof((x)[0])) @@ -54,6 +60,17 @@ long _dirreadall(int, Dir**); void _nulldir(Dir*); uint _sizeD2M(Dir*); +#define convM2D _convM2D +#define convD2M _convD2M +#define dirstat _dirstat +#define dirwstat _dirwstat +#define dirfstat _dirfstat +#define dirfwstat _dirfwstat +#define dirread _dirread +#define dirreadall _dirreadall +#define nulldir _nulldir +#define sizeD2M _sizeD2M + typedef struct Waitmsg { @@ -62,7 +79,6 @@ struct Waitmsg char *msg; } Waitmsg; - extern int _AWAIT(char*, int); extern int _ALARM(unsigned long); extern int _BIND(const char*, const char*, int); @@ -106,13 +122,14 @@ extern long _READN(int, void*, long); extern int _IOUNIT(int); extern vlong _NSEC(void); -#define dirstat _dirstat -#define dirfstat _dirfstat - #define OREAD 0 #define OWRITE 1 #define ORDWR 2 -#define OCEXEC 32 +#define OEXEC 3 /* execute, == read but check execute permission */ +#define OTRUNC 16 /* or'ed in (except for exec), truncate file first */ +#define OCEXEC 32 /* or'ed in, close on exec */ +#define ORCLOSE 64 /* or'ed in, remove on close */ +#define OEXCL 0x1000 /* or'ed in, exclusive use (create only) */ #define AREAD 4 #define AWRITE 2 @@ -125,6 +142,8 @@ extern vlong _NSEC(void); #define create(file, omode, perm) open(file, (omode) |O_CREAT | O_TRUNC, perm) #define seek(fd, off, dir) lseek(fd, off, dir) +#define fauth _FAUTH +#define wait _WAIT #define readn _READN #define pread _PREAD #define pwrite _PWRITE @@ -132,11 +151,15 @@ extern vlong _NSEC(void); #define nsec _NSEC #define iounit _IOUNIT +#define getwd(buf,len) getcwd(buf,len) #define postnote(who,pid,note) kill(pid,SIGTERM) #define atnotify(func,in) #define ERRMAX 128 +int errstr(char*, unsigned int); +extern void sysfatal(char*, ...); + extern void setmalloctag(void*, uintptr_t); extern void setrealloctag(void*, uintptr_t); extern uintptr_t getcallerpc(void*); @@ -148,6 +171,29 @@ extern int enc32(char *, int, uchar *, int); extern int dec64(uchar *, int, char *, int); extern int enc64(char *, int, uchar *, int); -extern int tokenize(char*, char**, int); -extern void sysfatal(char*, ...); -extern ulong truerand(void); /* uses /dev/random */ +extern int tokenize(char*, char**, int); +extern int getfields(char*, char**, int, int, char*); +extern int gettokens(char*, char**, int, char*); + +extern ulong truerand(void); /* uses /dev/random */ + +extern int encrypt(void*, void*, int len); +extern int decrypt(void*, void*, int len); + +typedef +struct Tm +{ + int sec; + int min; + int hour; + int mday; + int mon; + int year; + int wday; + int yday; + char zone[4]; + int tzoff; +} Tm; + +Tm* _gmtime(time_t); +#define gmtime _gmtime diff --git a/sys/src/ape/lib/9/mkfile b/sys/src/ape/lib/9/mkfile index cc3e5b9b8..f3e9d7f4f 100644 --- a/sys/src/ape/lib/9/mkfile +++ b/sys/src/ape/lib/9/mkfile @@ -2,11 +2,15 @@ APE=/sys/src/ape <$APE/config LIB=/$objtype/lib/ape/lib9.a -OFILES=argv0.$O\ - errstr.$O\ +OFILES=\ + argv0.$O\ bind.$O\ + crypt.$O\ + ctime.$O\ + errstr.$O\ getcallerpc.$O\ getfcr.$O\ + getfields.$O\ mount.$O\ rendezvous.$O\ rfork.$O\ @@ -40,9 +44,15 @@ CFLAGS=-c $CFLAGS -D_POSIX_SOURCE -D_PLAN9_SOURCE sysfatal.$O: ../../../libc/9sys/sysfatal.c $CC $CFLAGS -I. ../../../libc/9sys/sysfatal.c +getfields.$O: ../../../libc/port/getfields.c + $CC $CFLAGS -I. ../../../libc/port/getfields.c + tokenize.$O: ../../../libc/port/tokenize.c $CC $CFLAGS -I. ../../../libc/port/tokenize.c +crypt.$O: ../../../libc/port/crypt.c + $CC $CFLAGS -I. ../../../libc/port/crypt.c + truerand.$O: ../../../libc/9sys/truerand.c $CC $CFLAGS -I. ../../../libc/9sys/truerand.c diff --git a/sys/src/ape/lib/auth/authsrv.h b/sys/src/ape/lib/auth/authsrv.h new file mode 100644 index 000000000..498dc9870 --- /dev/null +++ b/sys/src/ape/lib/auth/authsrv.h @@ -0,0 +1,45 @@ +enum +{ + ANAMELEN= 28, /* name max size in previous proto */ + AERRLEN= 64, /* errstr max size in previous proto */ + DOMLEN= 48, /* authentication domain name length */ + DESKEYLEN= 7, /* encrypt/decrypt des key length */ + AESKEYLEN= 16, /* encrypt/decrypt aes key length */ + + CHALLEN= 8, /* plan9 sk1 challenge length */ + NETCHLEN= 16, /* max network challenge length (used in AS protocol) */ + CONFIGLEN= 14, + SECRETLEN= 32, /* secret max size */ + + NONCELEN= 32, + + KEYDBOFF= 8, /* bytes of random data at key file's start */ + OKEYDBLEN= ANAMELEN+DESKEYLEN+4+2, /* old key file entry length */ + KEYDBLEN= OKEYDBLEN+SECRETLEN, /* key file entry length */ + OMD5LEN= 16, + + /* AuthPAK constants */ + PAKKEYLEN= 32, + PAKSLEN= (448+7)/8, /* ed448 scalar */ + PAKPLEN= 4*PAKSLEN, /* point in extended format X,Y,Z,T */ + PAKHASHLEN= 2*PAKPLEN, /* hashed points PM,PN */ + PAKXLEN= PAKSLEN, /* random scalar secret key */ + PAKYLEN= PAKSLEN, /* decaf encoded public key */ +}; + +typedef struct Authkey Authkey; +struct Authkey +{ + char des[DESKEYLEN]; /* DES key from password */ + uchar aes[AESKEYLEN]; /* AES key from password */ + uchar pakkey[PAKKEYLEN]; /* shared key from AuthPAK exchange (see authpak_finish()) */ + uchar pakhash[PAKHASHLEN]; /* secret hash from AES key and user name (see authpak_hash()) */ +}; + +/* + * convert ascii password to auth key + */ +extern void passtokey(Authkey*, char*); + +extern void passtodeskey(char key[DESKEYLEN], char *p); +extern void passtoaeskey(uchar key[AESKEYLEN], char *p); diff --git a/sys/src/ape/lib/auth/fcall.h b/sys/src/ape/lib/auth/fcall.h new file mode 100644 index 000000000..6da9bbe1d --- /dev/null +++ b/sys/src/ape/lib/auth/fcall.h @@ -0,0 +1,20 @@ +#define VERSION9P "9P2000" +#define MAXWELEM 16 + +#define GBIT8(p) ((p)[0]) +#define GBIT16(p) ((p)[0]|((p)[1]<<8)) +#define GBIT32(p) ((p)[0]|((p)[1]<<8)|((p)[2]<<16)|((p)[3]<<24)) +#define GBIT64(p) ((u32int)((p)[0]|((p)[1]<<8)|((p)[2]<<16)|((p)[3]<<24)) |\ + ((vlong)((p)[4]|((p)[5]<<8)|((p)[6]<<16)|((p)[7]<<24)) << 32)) + +#define PBIT8(p,v) (p)[0]=(v) +#define PBIT16(p,v) (p)[0]=(v);(p)[1]=(v)>>8 +#define PBIT32(p,v) (p)[0]=(v);(p)[1]=(v)>>8;(p)[2]=(v)>>16;(p)[3]=(v)>>24 +#define PBIT64(p,v) (p)[0]=(v);(p)[1]=(v)>>8;(p)[2]=(v)>>16;(p)[3]=(v)>>24;\ + (p)[4]=(v)>>32;(p)[5]=(v)>>40;(p)[6]=(v)>>48;(p)[7]=(v)>>56 + +#define BIT8SZ 1 +#define BIT16SZ 2 +#define BIT32SZ 4 +#define BIT64SZ 8 +#define QIDSZ (BIT8SZ+BIT32SZ+BIT64SZ) diff --git a/sys/src/ape/lib/auth/mkfile b/sys/src/ape/lib/auth/mkfile new file mode 100644 index 000000000..fa30d3a83 --- /dev/null +++ b/sys/src/ape/lib/auth/mkfile @@ -0,0 +1,43 @@ +APE=/sys/src/ape +<$APE/config + +LIB=/$objtype/lib/ape/libauth.a +OFILES=\ + amount.$O\ + amount_getkey.$O\ + attr.$O\ + auth_attr.$O\ + auth_challenge.$O\ + auth_chuid.$O\ + auth_getkey.$O\ + auth_getuserpasswd.$O\ + auth_proxy.$O\ + auth_respond.$O\ + auth_rpc.$O\ + auth_userpasswd.$O\ + auth_wep.$O\ + login.$O\ + newns.$O\ + noworld.$O\ + passtokey.$O\ + +HFILES=\ + /sys/include/ape/auth.h\ + /sys/src/libauth/authlocal.h\ + ../9/libc.h + +UPDATE=\ + mkfile\ + $HFILES\ + ${OFILES:%.$O=%.c}\ + ${LIB:/$objtype/%=/386/%}\ + + +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include + +int debug, auth, dialfile; +char *keyspec = ""; +char *servername, *file, *filex, *ccert; + +void +sysfatal(char *fmt, ...) +{ + va_list a; + + va_start(a, fmt); + vfprintf(stderr, fmt, a); + va_end(a); + fprintf(stderr, "\n"); + exit(1); +} + +void +usage(void) +{ + fprint(2, "usage: tlsclient [-D] [-a [-k keyspec] ] [-c lib/tls/clientcert] [-t /sys/lib/tls/xxx] [-x /sys/lib/tls/xxx.exclude] [-n servername] [-o] dialstring [cmd [args...]]\n"); + exit(1); +} + +void +xfer(int from, int to) +{ + char buf[12*1024]; + int n; + + while((n = read(from, buf, sizeof buf)) > 0) + if(write(to, buf, n) < 0) + break; +} + +static int +reporter(char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + fprint(2, "%s: tls reports ", argv0); + vfprint(2, fmt, ap); + fprint(2, "\n"); + + va_end(ap); + return 0; +} + +int +main(int argc, char **argv) +{ + int fd, pid; + char *addr; + TLSconn *conn; + Thumbprint *thumb; + AuthInfo *ai = nil; + +// fmtinstall('H', encodefmt); + + ARGBEGIN{ + case 'D': + debug++; + break; + case 'a': + auth++; + break; + case 'k': + keyspec = EARGF(usage()); + break; + case 't': + file = EARGF(usage()); + break; + case 'x': + filex = EARGF(usage()); + break; + case 'c': + ccert = EARGF(usage()); + break; + case 'n': + servername = EARGF(usage()); + break; + case 'o': + dialfile = 1; + break; + default: + usage(); + }ARGEND + + if(argc < 1) + usage(); + + if(filex && !file) + sysfatal("specifying -x without -t is useless"); + + if(file){ + thumb = initThumbprints(file, filex); + if(thumb == nil) + sysfatal("initThumbprints: %r"); + } else + thumb = nil; + + addr = *argv++; + if((fd = dial(addr, 0, 0, 0)) < 0) + sysfatal("dial %s: %r", addr); + + conn = (TLSconn*)malloc(sizeof *conn); + memset(conn, 0, sizeof(*conn)); + conn->serverName = servername; + if(ccert){ + conn->cert = readcert(ccert, &conn->certlen); + if(conn->cert == nil) + sysfatal("readcert: %r"); + } + + if(auth){ + ai = auth_proxy(fd, auth_getkey, "proto=p9any role=client %s", keyspec); + if(ai == nil) + sysfatal("auth_proxy: %r"); + + conn->pskID = "p9secret"; + conn->psk = ai->secret; + conn->psklen = ai->nsecret; + } + + if(debug) + conn->trace = reporter; + + fd = tlsClient(fd, conn); + if(fd < 0) + sysfatal("tlsclient: %r"); + + if(thumb){ + uchar digest[20]; + + if(conn->cert==nil || conn->certlen<=0) + sysfatal("server did not provide TLS certificate"); + sha1(conn->cert, conn->certlen, digest, nil); + if(!okThumbprint(digest, thumb)) + sysfatal("server certificate %.*H not recognized", SHA1dlen, digest); + freeThumbprints(thumb); + } + + free(conn->cert); + free(conn->sessionID); + free(conn); + if(ai != nil) + auth_freeAI(ai); + + pid = fork(); + switch(pid){ + case -1: + sysfatal("fork: %r"); + case 0: + pid = getppid(); + xfer(0, fd); + break; + default: + xfer(fd, 1); + break; + } + if(pid) kill(pid, SIGTERM); + return 0; +}