static void mrb_ecdsa_free(mrb_state *mrb, void *ptr) { ecdsa_context *ecdsa = ptr; if (ecdsa != NULL) { ecdsa_free(ecdsa); } }
void free_connection(connection_t *c) { if(!c) return; cipher_close(c->incipher); digest_close(c->indigest); cipher_close(c->outcipher); digest_close(c->outdigest); sptps_stop(&c->sptps); ecdsa_free(c->ecdsa); rsa_free(c->rsa); free(c->hischallenge); buffer_clear(&c->inbuf); buffer_clear(&c->outbuf); io_del(&c->io); if(c->socket > 0) closesocket(c->socket); free(c->name); free(c->hostname); if(c->config_tree) exit_configuration(&c->config_tree); free(c); }
static int eckey_verify_wrap( void *ctx, md_type_t md_alg, const unsigned char *hash, size_t hash_len, const unsigned char *sig, size_t sig_len ) { int ret; ecdsa_context ecdsa; ecdsa_init( &ecdsa ); if( ( ret = ecdsa_from_keypair( &ecdsa, ctx ) ) == 0 ) ret = ecdsa_verify_wrap( &ecdsa, md_alg, hash, hash_len, sig, sig_len ); ecdsa_free( &ecdsa ); return( ret ); }
static int eckey_sign_wrap( void *ctx, md_type_t md_alg, const unsigned char *hash, size_t hash_len, unsigned char *sig, size_t *sig_len, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) { int ret; ecdsa_context ecdsa; ecdsa_init( &ecdsa ); if( ( ret = ecdsa_from_keypair( &ecdsa, ctx ) ) == 0 ) ret = ecdsa_sign_wrap( &ecdsa, md_alg, hash, hash_len, sig, sig_len, f_rng, p_rng ); ecdsa_free( &ecdsa ); return( ret ); }
static bool read_invitation_key(meshlink_handle_t *mesh) { FILE *fp; char filename[PATH_MAX]; if(mesh->invitation_key) { ecdsa_free(mesh->invitation_key); mesh->invitation_key = NULL; } snprintf(filename,PATH_MAX, "%s" SLASH "invitations" SLASH "ecdsa_key.priv", mesh->confbase); fp = fopen(filename, "rb"); if(fp) { mesh->invitation_key = ecdsa_read_pem_private_key(fp); fclose(fp); if(!mesh->invitation_key) logger(mesh, MESHLINK_ERROR, "Reading ECDSA private key file `%s' failed: %s", filename, strerror(errno)); } return mesh->invitation_key; }
void free_connection(connection_t *c) { if(!c) return; sptps_stop(&c->sptps); ecdsa_free(c->ecdsa); buffer_clear(&c->inbuf); buffer_clear(&c->outbuf); if(c->io.cb) abort(); if(c->socket > 0) closesocket(c->socket); free(c->name); free(c->hostname); if(c->config_tree) exit_configuration(&c->config_tree); free(c); }
static void ecdsa_free_wrap( void *ctx ) { ecdsa_free( (ecdsa_context *) ctx ); polarssl_free( ctx ); }
int main( int argc, char *argv[] ) { int ret; ecdsa_context ctx_sign, ctx_verify; entropy_context entropy; ctr_drbg_context ctr_drbg; unsigned char hash[] = "This should be the hash of a message."; unsigned char sig[512]; size_t sig_len; const char *pers = "ecdsa"; ((void) argv); ecdsa_init( &ctx_sign ); ecdsa_init( &ctx_verify ); memset(sig, 0, sizeof( sig ) ); ret = 1; if( argc != 1 ) { polarssl_printf( "usage: ecdsa\n" ); #if defined(_WIN32) polarssl_printf( "\n" ); #endif goto exit; } /* * Generate a key pair for signing */ polarssl_printf( "\n . Seeding the random number generator..." ); fflush( stdout ); entropy_init( &entropy ); if( ( ret = ctr_drbg_init( &ctr_drbg, entropy_func, &entropy, (const unsigned char *) pers, strlen( pers ) ) ) != 0 ) { polarssl_printf( " failed\n ! ctr_drbg_init returned %d\n", ret ); goto exit; } polarssl_printf( " ok\n . Generating key pair..." ); fflush( stdout ); if( ( ret = ecdsa_genkey( &ctx_sign, ECPARAMS, ctr_drbg_random, &ctr_drbg ) ) != 0 ) { polarssl_printf( " failed\n ! ecdsa_genkey returned %d\n", ret ); goto exit; } polarssl_printf( " ok (key size: %d bits)\n", (int) ctx_sign.grp.pbits ); dump_pubkey( " + Public key: ", &ctx_sign ); /* * Sign some message hash */ polarssl_printf( " . Signing message..." ); fflush( stdout ); if( ( ret = ecdsa_write_signature( &ctx_sign, hash, sizeof( hash ), sig, &sig_len, ctr_drbg_random, &ctr_drbg ) ) != 0 ) { polarssl_printf( " failed\n ! ecdsa_genkey returned %d\n", ret ); goto exit; } polarssl_printf( " ok (signature length = %u)\n", (unsigned int) sig_len ); dump_buf( " + Hash: ", hash, sizeof hash ); dump_buf( " + Signature: ", sig, sig_len ); /* * Signature is serialized as defined by RFC 4492 p. 20, * but one can also access 'r' and 's' directly from the context */ #ifdef POLARSSL_FS_IO mpi_write_file( " r = ", &ctx_sign.r, 16, NULL ); mpi_write_file( " s = ", &ctx_sign.s, 16, NULL ); #endif /* * Transfer public information to verifying context * * We could use the same context for verification and signatures, but we * chose to use a new one in order to make it clear that the verifying * context only needs the public key (Q), and not the private key (d). */ polarssl_printf( " . Preparing verification context..." ); fflush( stdout ); if( ( ret = ecp_group_copy( &ctx_verify.grp, &ctx_sign.grp ) ) != 0 ) { polarssl_printf( " failed\n ! ecp_group_copy returned %d\n", ret ); goto exit; } if( ( ret = ecp_copy( &ctx_verify.Q, &ctx_sign.Q ) ) != 0 ) { polarssl_printf( " failed\n ! ecp_copy returned %d\n", ret ); goto exit; } ret = 0; /* * Verify signature */ polarssl_printf( " ok\n . Verifying signature..." ); fflush( stdout ); if( ( ret = ecdsa_read_signature( &ctx_verify, hash, sizeof( hash ), sig, sig_len ) ) != 0 ) { polarssl_printf( " failed\n ! ecdsa_read_signature returned %d\n", ret ); goto exit; } polarssl_printf( " ok\n" ); exit: #if defined(_WIN32) polarssl_printf( " + Press Enter to exit this program.\n" ); fflush( stdout ); getchar(); #endif ecdsa_free( &ctx_verify ); ecdsa_free( &ctx_sign ); ctr_drbg_free( &ctr_drbg ); entropy_free( &entropy ); return( ret ); }
int cmd_join(int argc, char *argv[]) { free(data); data = NULL; datalen = 0; if(argc > 2) { fprintf(stderr, "Too many arguments!\n"); return 1; } // Make sure confbase exists and is accessible. if(!confbase_given && mkdir(confdir, 0755) && errno != EEXIST) { fprintf(stderr, "Could not create directory %s: %s\n", confdir, strerror(errno)); return 1; } if(mkdir(confbase, 0777) && errno != EEXIST) { fprintf(stderr, "Could not create directory %s: %s\n", confbase, strerror(errno)); return 1; } if(access(confbase, R_OK | W_OK | X_OK)) { fprintf(stderr, "No permission to write in directory %s: %s\n", confbase, strerror(errno)); return 1; } // If a netname or explicit configuration directory is specified, check for an existing tinc.conf. if((netname || confbasegiven) && !access(tinc_conf, F_OK)) { fprintf(stderr, "Configuration file %s already exists!\n", tinc_conf); return 1; } // Either read the invitation from the command line or from stdin. char *invitation; if(argc > 1) { invitation = argv[1]; } else { if(tty) fprintf(stderr, "Enter invitation URL: "); errno = EPIPE; if(!fgets(line, sizeof line, stdin)) { fprintf(stderr, "Error while reading stdin: %s\n", strerror(errno)); return false; } invitation = line; } // Parse the invitation URL. rstrip(line); char *slash = strchr(invitation, '/'); if(!slash) goto invalid; *slash++ = 0; if(strlen(slash) != 48) goto invalid; char *address = invitation; char *port = NULL; if(*address == '[') { address++; char *bracket = strchr(address, ']'); if(!bracket) goto invalid; *bracket = 0; if(bracket[1] == ':') port = bracket + 2; } else { port = strchr(address, ':'); if(port) *port++ = 0; } if(!port || !*port) port = "655"; if(!b64decode(slash, hash, 24) || !b64decode(slash + 24, cookie, 24)) goto invalid; // Generate a throw-away key for the invitation. ecdsa_t *key = ecdsa_generate(); if(!key) return 1; char *b64key = ecdsa_get_base64_public_key(key); // Connect to the tinc daemon mentioned in the URL. struct addrinfo *ai = str2addrinfo(address, port, SOCK_STREAM); if(!ai) return 1; struct addrinfo *aip = NULL; next: if(!aip) aip = ai; else { aip = aip->ai_next; if(!aip) return 1; } sock = socket(aip->ai_family, aip->ai_socktype, aip->ai_protocol); if(sock <= 0) { fprintf(stderr, "Could not open socket: %s\n", strerror(errno)); goto next; } if(connect(sock, aip->ai_addr, aip->ai_addrlen)) { char *addrstr, *portstr; sockaddr2str((sockaddr_t *)aip->ai_addr, &addrstr, &portstr); fprintf(stderr, "Could not connect to %s port %s: %s\n", addrstr, portstr, strerror(errno)); free(addrstr); free(portstr); closesocket(sock); goto next; } fprintf(stderr, "Connected to %s port %s...\n", address, port); // Tell him we have an invitation, and give him our throw-away key. int len = snprintf(line, sizeof line, "0 ?%s %d.%d\n", b64key, PROT_MAJOR, PROT_MINOR); if(len <= 0 || len >= sizeof line) abort(); if(!sendline(sock, "0 ?%s %d.%d", b64key, PROT_MAJOR, 1)) { fprintf(stderr, "Error sending request to %s port %s: %s\n", address, port, strerror(errno)); closesocket(sock); goto next; } char hisname[4096] = ""; int code, hismajor, hisminor = 0; if(!recvline(sock, line, sizeof line) || sscanf(line, "%d %s %d.%d", &code, hisname, &hismajor, &hisminor) < 3 || code != 0 || hismajor != PROT_MAJOR || !check_id(hisname) || !recvline(sock, line, sizeof line) || !rstrip(line) || sscanf(line, "%d ", &code) != 1 || code != ACK || strlen(line) < 3) { fprintf(stderr, "Cannot read greeting from peer\n"); closesocket(sock); goto next; } // Check if the hash of the key he gave us matches the hash in the URL. char *fingerprint = line + 2; char hishash[64]; if(sha512(fingerprint, strlen(fingerprint), hishash)) { fprintf(stderr, "Could not create digest\n%s\n", line + 2); return 1; } if(memcmp(hishash, hash, 18)) { fprintf(stderr, "Peer has an invalid key!\n%s\n", line + 2); return 1; } ecdsa_t *hiskey = ecdsa_set_base64_public_key(fingerprint); if(!hiskey) return 1; // Start an SPTPS session if(!sptps_start(&sptps, NULL, true, false, key, hiskey, "tinc invitation", 15, invitation_send, invitation_receive)) return 1; // Feed rest of input buffer to SPTPS if(!sptps_receive_data(&sptps, buffer, blen)) return 1; while((len = recv(sock, line, sizeof line, 0))) { if(len < 0) { if(errno == EINTR) continue; fprintf(stderr, "Error reading data from %s port %s: %s\n", address, port, strerror(errno)); return 1; } char *p = line; while(len) { int done = sptps_receive_data(&sptps, p, len); if(!done) return 1; len -= done; p += done; } } sptps_stop(&sptps); ecdsa_free(hiskey); ecdsa_free(key); closesocket(sock); if(!success) { fprintf(stderr, "Connection closed by peer, invitation cancelled.\n"); return 1; } return 0; invalid: fprintf(stderr, "Invalid invitation URL.\n"); return 1; }
static bool finalize_join(void) { char *name = xstrdup(get_value(data, "Name")); if(!name) { fprintf(stderr, "No Name found in invitation!\n"); return false; } if(!check_id(name)) { fprintf(stderr, "Invalid Name found in invitation: %s!\n", name); return false; } if(!netname) netname = grep(data, "NetName"); bool ask_netname = false; char temp_netname[32]; make_names: if(!confbasegiven) { free(confbase); confbase = NULL; } make_names(false); free(tinc_conf); free(hosts_dir); xasprintf(&tinc_conf, "%s" SLASH "tinc.conf", confbase); xasprintf(&hosts_dir, "%s" SLASH "hosts", confbase); if(!access(tinc_conf, F_OK)) { fprintf(stderr, "Configuration file %s already exists!\n", tinc_conf); if(confbasegiven) return false; // Generate a random netname, ask for a better one later. ask_netname = true; snprintf(temp_netname, sizeof temp_netname, "join_%x", rand()); netname = temp_netname; goto make_names; } if(mkdir(confbase, 0777) && errno != EEXIST) { fprintf(stderr, "Could not create directory %s: %s\n", confbase, strerror(errno)); return false; } if(mkdir(hosts_dir, 0777) && errno != EEXIST) { fprintf(stderr, "Could not create directory %s: %s\n", hosts_dir, strerror(errno)); return false; } FILE *f = fopen(tinc_conf, "w"); if(!f) { fprintf(stderr, "Could not create file %s: %s\n", tinc_conf, strerror(errno)); return false; } fprintf(f, "Name = %s\n", name); char filename[PATH_MAX]; snprintf(filename, sizeof filename, "%s" SLASH "%s", hosts_dir, name); FILE *fh = fopen(filename, "w"); if(!fh) { fprintf(stderr, "Could not create file %s: %s\n", filename, strerror(errno)); fclose(f); return false; } // Filter first chunk on approved keywords, split between tinc.conf and hosts/Name // Other chunks go unfiltered to their respective host config files const char *p = data; char *l, *value; while((l = get_line(&p))) { // Ignore comments if(*l == '#') continue; // Split line into variable and value int len = strcspn(l, "\t ="); value = l + len; value += strspn(value, "\t "); if(*value == '=') { value++; value += strspn(value, "\t "); } l[len] = 0; // Is it a Name? if(!strcasecmp(l, "Name")) if(strcmp(value, name)) break; else continue; else if(!strcasecmp(l, "NetName")) continue; // Check the list of known variables bool found = false; int i; for(i = 0; variables[i].name; i++) { if(strcasecmp(l, variables[i].name)) continue; found = true; break; } // Ignore unknown and unsafe variables if(!found) { fprintf(stderr, "Ignoring unknown variable '%s' in invitation.\n", l); continue; } else if(!(variables[i].type & VAR_SAFE)) { fprintf(stderr, "Ignoring unsafe variable '%s' in invitation.\n", l); continue; } // Copy the safe variable to the right config file fprintf(variables[i].type & VAR_HOST ? fh : f, "%s = %s\n", l, value); } fclose(f); while(l && !strcasecmp(l, "Name")) { if(!check_id(value)) { fprintf(stderr, "Invalid Name found in invitation.\n"); return false; } if(!strcmp(value, name)) { fprintf(stderr, "Secondary chunk would overwrite our own host config file.\n"); return false; } snprintf(filename, sizeof filename, "%s" SLASH "%s", hosts_dir, value); f = fopen(filename, "w"); if(!f) { fprintf(stderr, "Could not create file %s: %s\n", filename, strerror(errno)); return false; } while((l = get_line(&p))) { if(!strcmp(l, "#---------------------------------------------------------------#")) continue; int len = strcspn(l, "\t ="); if(len == 4 && !strncasecmp(l, "Name", 4)) { value = l + len; value += strspn(value, "\t "); if(*value == '=') { value++; value += strspn(value, "\t "); } l[len] = 0; break; } fputs(l, f); fputc('\n', f); } fclose(f); } // Generate our key and send a copy to the server ecdsa_t *key = ecdsa_generate(); if(!key) return false; char *b64key = ecdsa_get_base64_public_key(key); if(!b64key) return false; snprintf(filename, sizeof filename, "%s" SLASH "ed25519_key.priv", confbase); f = fopenmask(filename, "w", 0600); if(!f) return false; if(!ecdsa_write_pem_private_key(key, f)) { fprintf(stderr, "Error writing private key!\n"); ecdsa_free(key); fclose(f); return false; } fclose(f); fprintf(fh, "Ed25519PublicKey = %s\n", b64key); sptps_send_record(&sptps, 1, b64key, strlen(b64key)); free(b64key); ecdsa_free(key); check_port(name); ask_netname: if(ask_netname && tty) { fprintf(stderr, "Enter a new netname: "); if(!fgets(line, sizeof line, stdin)) { fprintf(stderr, "Error while reading stdin: %s\n", strerror(errno)); return false; } if(!*line || *line == '\n') goto ask_netname; line[strlen(line) - 1] = 0; char newbase[PATH_MAX]; snprintf(newbase, sizeof newbase, CONFDIR SLASH "tinc" SLASH "%s", line); if(rename(confbase, newbase)) { fprintf(stderr, "Error trying to rename %s to %s: %s\n", confbase, newbase, strerror(errno)); goto ask_netname; } netname = line; make_names(false); } fprintf(stderr, "Configuration stored in: %s\n", confbase); return true; }
int main(int argc, char *argv[]) { ecdsa_t *key1, *key2; ecdh_t *ecdh1, *ecdh2; sptps_t sptps1, sptps2; char buf1[4096], buf2[4096], buf3[4096]; double duration = argc > 1 ? atof(argv[1]) : 10; crypto_init(); randomize(buf1, sizeof buf1); randomize(buf2, sizeof buf2); randomize(buf3, sizeof buf3); // Key generation fprintf(stderr, "Generating keys for %lg seconds: ", duration); for(clock_start(); clock_countto(duration);) ecdsa_free(ecdsa_generate()); fprintf(stderr, "%17.2lf op/s\n", rate); key1 = ecdsa_generate(); key2 = ecdsa_generate(); // Ed25519 signatures fprintf(stderr, "Ed25519 sign for %lg seconds: ", duration); for(clock_start(); clock_countto(duration);) if(!ecdsa_sign(key1, buf1, 256, buf2)) return 1; fprintf(stderr, "%20.2lf op/s\n", rate); fprintf(stderr, "Ed25519 verify for %lg seconds: ", duration); for(clock_start(); clock_countto(duration);) if(!ecdsa_verify(key1, buf1, 256, buf2)) { fprintf(stderr, "Signature verification failed\n"); return 1; } fprintf(stderr, "%18.2lf op/s\n", rate); ecdh1 = ecdh_generate_public(buf1); fprintf(stderr, "ECDH for %lg seconds: ", duration); for(clock_start(); clock_countto(duration);) { ecdh2 = ecdh_generate_public(buf2); if(!ecdh2) return 1; if(!ecdh_compute_shared(ecdh2, buf1, buf3)) return 1; } fprintf(stderr, "%28.2lf op/s\n", rate); ecdh_free(ecdh1); // SPTPS authentication phase int fd[2]; if(socketpair(AF_UNIX, SOCK_STREAM, 0, fd)) { fprintf(stderr, "Could not create a UNIX socket pair: %s\n", sockstrerror(sockerrno)); return 1; } struct pollfd pfd[2] = {{fd[0], POLLIN}, {fd[1], POLLIN}}; fprintf(stderr, "SPTPS/TCP authenticate for %lg seconds: ", duration); for(clock_start(); clock_countto(duration);) { sptps_start(&sptps1, fd + 0, true, false, key1, key2, "sptps_speed", 11, send_data, receive_record); sptps_start(&sptps2, fd + 1, false, false, key2, key1, "sptps_speed", 11, send_data, receive_record); while(poll(pfd, 2, 0)) { if(pfd[0].revents) receive_data(&sptps1); if(pfd[1].revents) receive_data(&sptps2); } sptps_stop(&sptps1); sptps_stop(&sptps2); } fprintf(stderr, "%10.2lf op/s\n", rate * 2); // SPTPS data sptps_start(&sptps1, fd + 0, true, false, key1, key2, "sptps_speed", 11, send_data, receive_record); sptps_start(&sptps2, fd + 1, false, false, key2, key1, "sptps_speed", 11, send_data, receive_record); while(poll(pfd, 2, 0)) { if(pfd[0].revents) receive_data(&sptps1); if(pfd[1].revents) receive_data(&sptps2); } fprintf(stderr, "SPTPS/TCP transmit for %lg seconds: ", duration); for(clock_start(); clock_countto(duration);) { if(!sptps_send_record(&sptps1, 0, buf1, 1451)) abort(); receive_data(&sptps2); } rate *= 2 * 1451 * 8; if(rate > 1e9) fprintf(stderr, "%14.2lf Gbit/s\n", rate / 1e9); else if(rate > 1e6) fprintf(stderr, "%14.2lf Mbit/s\n", rate / 1e6); else if(rate > 1e3) fprintf(stderr, "%14.2lf kbit/s\n", rate / 1e3); sptps_stop(&sptps1); sptps_stop(&sptps2); // SPTPS datagram authentication phase close(fd[0]); close(fd[1]); if(socketpair(AF_UNIX, SOCK_DGRAM, 0, fd)) { fprintf(stderr, "Could not create a UNIX socket pair: %s\n", sockstrerror(sockerrno)); return 1; } fprintf(stderr, "SPTPS/UDP authenticate for %lg seconds: ", duration); for(clock_start(); clock_countto(duration);) { sptps_start(&sptps1, fd + 0, true, true, key1, key2, "sptps_speed", 11, send_data, receive_record); sptps_start(&sptps2, fd + 1, false, true, key2, key1, "sptps_speed", 11, send_data, receive_record); while(poll(pfd, 2, 0)) { if(pfd[0].revents) receive_data(&sptps1); if(pfd[1].revents) receive_data(&sptps2); } sptps_stop(&sptps1); sptps_stop(&sptps2); } fprintf(stderr, "%10.2lf op/s\n", rate * 2); // SPTPS datagram data sptps_start(&sptps1, fd + 0, true, true, key1, key2, "sptps_speed", 11, send_data, receive_record); sptps_start(&sptps2, fd + 1, false, true, key2, key1, "sptps_speed", 11, send_data, receive_record); while(poll(pfd, 2, 0)) { if(pfd[0].revents) receive_data(&sptps1); if(pfd[1].revents) receive_data(&sptps2); } fprintf(stderr, "SPTPS/UDP transmit for %lg seconds: ", duration); for(clock_start(); clock_countto(duration);) { if(!sptps_send_record(&sptps1, 0, buf1, 1451)) abort(); receive_data(&sptps2); } rate *= 2 * 1451 * 8; if(rate > 1e9) fprintf(stderr, "%14.2lf Gbit/s\n", rate / 1e9); else if(rate > 1e6) fprintf(stderr, "%14.2lf Mbit/s\n", rate / 1e6); else if(rate > 1e3) fprintf(stderr, "%14.2lf kbit/s\n", rate / 1e3); sptps_stop(&sptps1); sptps_stop(&sptps2); // Clean up close(fd[0]); close(fd[1]); ecdsa_free(key1); ecdsa_free(key2); crypto_exit(); return 0; }