Pieter, Laurent, Lindley--
Many thanks for the responses.
Laurent's mention of secure public key exchange got me thinking.
=== A Quick Trip to a Perfect World?
As to the global, high-level view of this curve stuff,
What If:
A. Every Server and Every Client creates a brand-new, fresh zcert for
itself in memory.
Between the server and its clients, all they need is each other's public
keys, and they can communicate securely.
B. Before connect time, we still "apply" the zcert to socket. Now, the
socket has both
public and private keys for our side of the secure connection.
C. At connection time, the underlying socket mechanisms should go ahead and
use the
Diffie-Hellman-Merkle-whoever Algorithm so the server can securely pass
its public key to the
client sockets, and each client can pass its public key to the server
socket.
We can then get rid of the zsocket_curve_serverkey and the
zsocket_set_curve_server_key and
zsocket_set_curve_server_key_bin sockopt functions. Hmmm... there's no
such thing as the
zsocket_set_curve_client_key funcs, so this already must be handled somehow
<murf shuffles
thru documentation for a while, and then quits>.
I'd imagine that this would also destroy completely the use of a
zcertstore...? It looks
like storing the public keys on disk was mainly for VERIFICATION. The
mechanism will compare
the public key with the store, and if it's there, then all is right with
the world. If not,
reject the connection.
I like the idea of the whitelist, but my applications have possibly
hundreds/thousands of machines
to run from and on, machines and networks go up and down like some infernal
game of basketball,
where every player has a basketball! Apps will be started on one machine,
go down, and get started
again on another. Entering single IP's and maintaining a list would be a
scary nightmare.
But, address RANGES might be easier to maintain, as each data center has a
fairly stable range of addresses
allocated. Even then, ... I can't help thinking... isn't this something a
separate firewall could do, or,
perhaps, a VPN, or something, so not just anyone can join in the fun?
=== Back to the current, real world.
I wrote a small program. I call it gen_cert.c:
#include <stdio.h>
#include <czmq.h>
int main(int argc, char ** argv)
{
char *a = argv[1]; // name of cert
uint8_t priv[32];
uint8_t pub[32];
zcert_t *cert = zcert_new();
uint8_t *privp = zcert_secret_key(cert);
uint8_t *pubp = zcert_public_key(cert);
memmove(priv, privp, sizeof(priv));
memmove(pub, pubp, sizeof(pub));
char *cprivp = zcert_secret_txt(cert);
char *cpubp = zcert_public_txt(cert);
printf("char *%s_private_txt = \"%s\";\n", a, cprivp);
printf("char *%s_public_txt = \"%s\";\n\n\n", a, cpubp);
zcert_save(cert, a);
printf("uint8_t %s_private[32] =
{0x%hhx,0x%hhx,0x%hhx,0x%hhx,0x%hhx,0x%hhx,0x%hhx,0x%hhx,\n
0x%hhx,0x%hhx,0x%hhx,0x%hhx,0x%hhx,0x%hhx,0x%hhx,0x%hhx,\n
0x%hhx,0x%hhx,0x%hhx,0x%hhx,0x%hhx,0x%hhx,0x%hhx,0x%hhx,\n
0x%hhx,0x%hhx,0x%hhx,0x%hhx,0x%hhx,0x%hhx,0x%hhx,0x%hhx };\n", a,
priv[0], priv[1], priv[2], priv[3], priv[4], priv[5], priv[6],
priv[7],
priv[8], priv[9], priv[10], priv[11], priv[12], priv[13],
priv[14], priv[15],
priv[16], priv[17], priv[18], priv[19], priv[20], priv[21],
priv[22], priv[23],
priv[24], priv[25], priv[26], priv[27], priv[28], priv[29],
priv[30], priv[31]);
printf("uint8_t %s_public[32] =
{0x%hhx,0x%hhx,0x%hhx,0x%hhx,0x%hhx,0x%hhx,0x%hhx,0x%hhx,\n
0x%hhx,0x%hhx,0x%hhx,0x%hhx,0x%hhx,0x%hhx,0x%hhx,0x%hhx,\n
0x%hhx,0x%hhx,0x%hhx,0x%hhx,0x%hhx,0x%hhx,0x%hhx,0x%hhx,\n
0x%hhx,0x%hhx,0x%hhx,0x%hhx,0x%hhx,0x%hhx,0x%hhx,0x%hhx };\n", a,
pub[0], pub[1], pub[2], pub[3], pub[4], pub[5], pub[6], pub[7],
pub[8], pub[9], pub[10], pub[11], pub[12], pub[13], pub[14],
pub[15],
pub[16], pub[17], pub[18], pub[19], pub[20], pub[21], pub[22],
pub[23],
pub[24], pub[25], pub[26], pub[27], pub[28], pub[29], pub[30],
pub[31]);
exit(0);
}
It generates certificates every which way it can. You give it a cert name
on the command line,
and it will generate a certificate file pair, and ascii (Z85?) string reps,
and C declarations for the binary.
I therewith generate a generic server key file pair, and a generic client
key file pair. I copy the two public key files to a storage directory on
all the machines.
I paste the server binary declarations into the server source code, and
same with the client declarations into the client. I throw away the
private/secret key files.
Yeah, it's not secure. When I get some time, I'll write a secure key server
or whatever. It's funny, but as far as I can tell, nothing is secure. At
least, they will be binary encoded into a stripped executable. Finding them
will be possible, hopefully just a little harder than grabbing a
certificate file. Mainly, our immediate goal is just to encrypt the
internet traffic.
On the server,
uint8_t srv_private[32] = {0x4d,
...
,0x7b };
uint8_t srv_public[32] = {0xbe,...
...
...,0xf2 };
zcert_t *cert = zcert_new_from(srv_public, srv_private);
zctx_t *ctx = zctx_new();
zauth_t *auth = zauth_new(ctx);
zauth_set_verbose (auth, true);
zauth_configure_curve(auth, "*", "/somewhere/certs");
void *server = zsocket_new(ctx, ZMQ_ROUTER);
zcert_apply(cert, server);
zsocket_set_curve_server(server, 1);
int pnum = zsocket_bind(server, url_string);
On the client:
uint8_t cl_private[32] = {0x29,
...
,0xf3 };
uint8_t cl_public[32] = {0x37,...
...
...,0x3e };
zauth_t *auth = zauth_new (ctx);
zauth_set_verbose (auth, true);
zauth_configure_curve (auth, "*", "/somewhere/certs");
zcert_t *cert = zcert_new_from(cl_public, cl_private);
zcert_t *server_cert = zcert_load("/somewhere/certs/servercert");
sock = zsocket_new(ctx, ZMQ_ROUTER);
zcert_apply (cert, sock);
zsocket_set_curve_serverkey (sock, zcert_public_txt(server_cert));
zsocket_connect(sock, url);
The above seems to work... yeah, not super secure, but no key exchange
over the network at run time (files distributed via sftp earlier).
Secret keys are indeed inside the exec, but... it will take a few
steps to locate them, but they first have to break into the machine(s)
involved, and know what to look for.
I'm quite new at this stuff, which makes me quite stupid. Please,
feel free to educate me! What can I do to make this setup better?
Will I have to work as a slave in the code mines for months to get it
right/acceptable?
murf
On Thu, Apr 3, 2014 at 4:29 AM, Pieter Hintjens <[email protected]> wrote:
> Hi Steve,
>
> Sorry that there are loose ends. It's a massive project and at about
> 80% I had to go back to paying work.
>
> zauth, zcert, and zcertstore form a package, you can understand, use,
> and improve them together. They implement a specific ZAP handler
> design based on simple text encoded certificates. It's not a great
> scheme and there's been a lot of discussion on better certificate
> formats... which leads nowhere.
>
> I had planned and will still someday write a guide to using this
> authentication layer. However for today what you have is the C code in
> CZMQ, the examples, and test cases. It is complex because of the
> unavoidable number of moving pieces. I've tried to avoid inventing
> random concepts, though.
>
> You are required to distribute public and secret keys yourself. The
> idea is to generate these as text files and then safely install them
> on clients and servers. CZMQ provides the server-side support for
> using them at runtime for authentication, though I don't think we
> covered how to use them for actual socket configuration.
>
> Like everything we do, it has to be driven by use and organic growth.
> So my advice is to treat CZMQ as something _we_ make together, find
> areas where you want to improve, and send us pull requests.
>
> Many thanks for the comments.
> -
> Pieter
>
>
>
> On Thu, Apr 3, 2014 at 1:50 AM, Steve Murphy <[email protected]> wrote:
> > OK, I've read the man pages for zcert, zcertstore, and zauth.
> > I've read the tutorial about the wood, stone, and iron houses.
> > I've compiled those examples, and run them, shoot, I even
> > wiresharked the ports and captured the conversations to see
> > the unencrypted vs. encryped communication. Cool.
> >
> > But now, it's time to actually write up some code and use this
> > stuff in a real set of distributed applications, and I find the
> > docs very frustrating.
> >
> > Firstly, little to no explanation in zauth about curve parameters
> > "domain" and "location", and how to use them.
> >
> > Nextly, zcert gives us zcert_new_from(..) which takes byte* args,
> > but no zcert_new_from_txt(...) with char* args.
> >
> > The zcertstore manpage says "To actually create certificates on disk,
> > use the zcert_class in code, or the tools/makecert.c command line
> > tool, or any text editor." That's nice, but the only tool in
> zeromq-4.0.x is
> > tools/curve_keygen, and it doesn't create a file,
> > it just prints out the keys with some explanatory text, not even
> > in cert file format.
> >
> > The zmq_curve_keypair example code shows a call to "crypto_box_keypair"
> > instead of zmq_curve_keypair, which I assume is
> > a typo, probably left over from "legacy" versions of the
> > document prototype.
> >
> > All the examples use zcert_new(), and provide public keys up front
> > to the clients, with
> > no examples of actually doing a certificate store of just public
> > keys, and no in-program storage of secret keys. It's almost as if one
> > is forced to create and distribute secret key files. (there's load
> > and save options in czmq).
> >
> > Let's say I want to store all my public keys in /etc/something/store.
> > I can distribute that pretty easily to hundreds of machines.
> > I want to compile a secret key into my servers and clients, for their
> > respective usage. Clients can fetch the public keys from the disk
> > store dir. So can the servers. But, the feeling I get from actually
> > looking over the API's, is that the above is not the intended
> > usage case. There are no public functions to convert to/from binary
> > and string key representations. Well, OK, that's entirely fair,
> > therre is zmq_z85_decode and encode, but I have to wrap that
> > in a fair amount of code to yield something like
> > byte secret_key[] = { 0xaf, 0x39, 0x45, 0xc3, .... };
> > that I could compile into a program... if that is even the intended
> > best way to handle keys (shrug).
> >
> > Don't get me wrong. I realize this stuff is brand-spanking-shiny-new
> > and hot-off-the-press, and usage cases are in their infancy. I'd just
> > like to NOT charge off in a wildly different direction than what you
> > guys envision, and be left with code I may have to rewrite someday.
> >
> > Please, can someone with a higher level view give me some idea of how
> > I best attack this situation? What's the best way to use this in
> > production environments, where the server and client are not in the same
> > executable?
> >
> > Pieter, up to writing a "part 3" tutorial outlining separate
> > servers and clients, using disked public keys, etc?
> >
> > One or two variants of suggested "best practice" for clients and
> > servers will answer all my questions and get me up and running full
> > speed!
> >
> > Many thanks!
> >
> > murf
> >
> >
> > --
> >
> > Steve Murphy
> > ParseTree Corporation
> > 57 Lane 17
> > Cody, WY 82414
> > ✉ murf at parsetree dot com
> > ☎ 307-899-5535
> >
> >
> >
> > _______________________________________________
> > zeromq-dev mailing list
> > [email protected]
> > http://lists.zeromq.org/mailman/listinfo/zeromq-dev
> >
> _______________________________________________
> zeromq-dev mailing list
> [email protected]
> http://lists.zeromq.org/mailman/listinfo/zeromq-dev
>
--
Steve Murphy
ParseTree Corporation
57 Lane 17
Cody, WY 82414
✉ murf at parsetree dot com
☎ 307-899-5535
_______________________________________________
zeromq-dev mailing list
[email protected]
http://lists.zeromq.org/mailman/listinfo/zeromq-dev