static int test_sign(const char *private_key, const char *public_key, bool success) { char *sig = NULL; char *file = NULL; int ret = -1; sig = str_or_die("%s/sig", test_dir); file = __FILE__; if (sign(private_key, public_key, file, sig) < 0) { goto error; } if (!signature_init(public_key, NULL)) { goto error; } // Check if signature match check_goto(signature_verify(file, sig, false) == success, error); // Check signature against wrong file check_goto(signature_verify(sig, sig, false) == false, error); ret = 0; error: signature_deinit(); free(sig); return ret; }
int do_sunxi_boot_signature(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) { int ret; int m_ok = 1; ret = signature_verify("boot"); if(!ret) { ret = signature_verify("system"); } if(ret) { printf("signature verify failed\n"); __u32 private_start; __u32 private_size; __u32 erase_block_once=SIG_ERASE_BUFFER_SIZE; char last_back[SIG_SMALL_BUFFER_SIZE]; char* private_data = NULL; private_start = sunxi_partition_get_offset_byname("private"); private_size = sunxi_partition_get_size_byname("private") * 512; private_data = malloc(SIG_ERASE_BUFFER_SIZE); if(!private_data) { printf("not enough memory for sig erase\n"); private_data = last_back; erase_block_once = SIG_SMALL_BUFFER_SIZE; m_ok = 0; } memset(private_data,0xff,erase_block_once); while(private_size>=erase_block_once) { sunxi_flash_write(private_start,erase_block_once/512,private_data); private_start += erase_block_once/512; private_size -= erase_block_once; } if(private_size) { sunxi_flash_write(private_start,private_size/512,private_data); } if(m_ok) { free(private_data); } } return 0; }
static bool send_stream(char const *program, struct notify_info *notify, struct memory_block_data const *payload, struct signature_algorithm *sigalg, struct decompression_algorithm *decompalg) { struct decompressor decomp = { .pid = -1 }; size_t len; pid_t pid = -1; int pfds[2] = { -1, -1 }; int status; notification_send(notify, "s", 1); if (pipe(pfds) < 0) { perror("pipe(<pfds>)"); goto err; } pid = fork(); if (pid < 0) { perror("fork()"); goto err; } if (pid == 0) { char size_str[sizeof(size_t)*3 + 2]; char type_str[sizeof(unsigned int)*3 + 2]; if (!signature_setenv(sigalg)) { fprintf(stderr, "failed to export signature details\n"); _exit(1); } close(pfds[1]); if (dup2(pfds[0], 0) < 0) { perror("dup2()"); _exit(1); } if (pfds[0] != 0) close(pfds[0]); sprintf(size_str, "%zu", payload->len); sprintf(type_str, "%u", payload->type); execlp(program, program, "stream", type_str, size_str, NULL); perror("execlp()"); _exit(1); } close(pfds[0]); pfds[0] = -1; if (!decompressor_run(&decomp, decompalg, payload->mem.stream->fd, payload->mem.len)) { fprintf(stderr, "failed to start decompressor\n"); goto err; } for (len = 0; len < payload->len && !payload->mem.stream->is_eos;) { ssize_t l; /* \todo: implement decompressor */ l = tee(decomp.fd_out, pfds[1], payload->len - len, SPLICE_F_MORE); if (l == 0) payload->mem.stream->is_eos = true; else if (l < 0 && errno == EINTR) { continue; } else if (l < 0) { perror("tee()"); break; } notification_handle_read(notify, l); if (!signature_pipein(sigalg, decomp.fd_out, l)) break; len += l; } close(pfds[1]); pfds[1] = -1; if (!decompressor_wait(&decomp)) goto err; if (len != payload->len) { fprintf(stderr, "failed to read all payload data (%zu < %zu)\n", len, payload->len); goto err; } notification_send(notify, "w", 1); if (waitpid(pid, &status, 0) < 0) { perror("waitpid()"); goto err; } pid = -1; if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { fprintf(stderr, "program failed with %d\n", status); goto err; } notification_send(notify, "e\0", 2); return true; err: if (pfds[0] != -1) close(pfds[0]); if (pfds[1] != -1) close(pfds[0]); if (pid != -1) { kill(pid, SIGTERM); waitpid(pid, NULL, 0); } decompressor_wait(&decomp); notification_send(notify, "e\1", 2); return false; } static bool verify_signature(struct memory_block_signature const *signature, struct signature_algorithm *sigalg) { be32_t tmp; size_t len; unsigned char sig[MAX_SIGNATURE_SIZE]; if (!stream_data_read(signature->mem.stream, &tmp, sizeof tmp, false)) { fprintf(stderr, "failed to read signature length\n"); return false; } len = be32toh(tmp); if (len > sizeof sig) { fprintf(stderr, "signature too large (%zu)\n", len); return false; } if (!stream_data_read(signature->mem.stream, &sig, len, false)) { fprintf(stderr, "failed to read signature\n"); return false; } if (!signature_verify(sigalg, sig, len)) { fprintf(stderr, "failed to verify signature\n"); return false; } return true; }
/*Run a benchmark with different curve parameters and print CSV result to out *Comma-Separated Values (CSV), RFC 4180: http://tools.ietf.org/html/rfc4180 */ void benchmark(FILE* out, int i) { //Print CSV header fprintf(out, "Curve, Public key generation time, Signature generation time, Signature verification time, Operation time\r\n"); //If the illiterator is invalid use default illiterator if(i < 1) i = DEFAULT_TEST_ILLITERATOR; //Loop through all curves, since we're benchmarking them towards eachother. int curve_i; for(curve_i = 0;curve_i < NUMBER_OF_CURVES;curve_i++) { //Set initial timer clock_t start = clock(); int test_i; //Load curve domain_parameters curve = domain_parameters_init(); domain_parameters_load_curve(curve, curve_i); //Print curve name fprintf(out, "%s, ", curve->name); //Get a private key mpz_t d;mpz_init(d); mpz_sub_ui(d, curve->n, 2); //Private key must be between 1 and n-1 //Get a message to sign mpz_t m;mpz_init(m); mpz_sub_ui(m, curve->n, 2); //Must be between 1 and n-1 //NOTE: I assume we're using a hash algorithm giving result with the biggest bit-length possible //Initialize a signature signature sig = signature_init(); //Initialize public key point Q = point_init(); //Save time at the start of public key generation clock_t start_gen_Q = clock(); //Generate public key for(test_i = 0; test_i < i; test_i++) signature_generate_key(Q, d, curve); //Save time between public key generation and signature generation clock_t start_sign = clock(); //Generate signature for(test_i = 0; test_i < i; test_i++) signature_sign(sig, m, d, curve); //Save time between signature generation and signature verification clock_t start_verify = clock(); //Verify signature bool result; for(test_i = 0; test_i < i; test_i++) result = signature_verify(m, sig, Q, curve); //Save time after verification clock_t end_verify = clock(); //Clear variables mpz_clear(d); domain_parameters_clear(curve); signature_clear(sig); mpz_clear(m); //Save time before printing clock_t end = clock(); //Print public key generation time fprintf(out, "%.4f, ", ((double) (start_sign - start_gen_Q)) / CLOCKS_PER_SEC); //Print signature generation time fprintf(out, "%.4f, ", ((double) (start_verify - start_sign)) / CLOCKS_PER_SEC); //Print signature verification time fprintf(out, "%.4f, ", ((double) (end_verify - start_verify)) / CLOCKS_PER_SEC); //Print operation time if(result) fprintf(out, "%.4f", ((double) (end - start)) / CLOCKS_PER_SEC); else fprintf(out, "-1"); //print a new line fprintf(out, "\r\n"); //Acoording to RFC4180 this must be done with CLRF } }
static int dh_handshake(SSH_SESSION *session){ STRING *e,*f,*pubkey,*signature; int ret; switch(session->dh_handshake_state){ case DH_STATE_INIT: packet_clear_out(session); buffer_add_u8(session->out_buffer,SSH2_MSG_KEXDH_INIT); dh_generate_x(session); dh_generate_e(session); e=dh_get_e(session); buffer_add_ssh_string(session->out_buffer,e); ret=packet_send(session); free(e); session->dh_handshake_state=DH_STATE_INIT_TO_SEND; if(ret==SSH_ERROR) return ret; case DH_STATE_INIT_TO_SEND: ret=packet_flush(session,0); if(ret!=SSH_OK) return ret; // SSH_ERROR or SSH_AGAIN session->dh_handshake_state=DH_STATE_INIT_SENT; case DH_STATE_INIT_SENT: ret=packet_wait(session,SSH2_MSG_KEXDH_REPLY,1); if(ret != SSH_OK) return ret; pubkey=buffer_get_ssh_string(session->in_buffer); if(!pubkey){ ssh_set_error(session,SSH_FATAL,"No public key in packet"); return SSH_ERROR; } dh_import_pubkey(session,pubkey); f=buffer_get_ssh_string(session->in_buffer); if(!f){ ssh_set_error(session,SSH_FATAL,"No F number in packet"); return SSH_ERROR; } dh_import_f(session,f); free(f); if(!(signature=buffer_get_ssh_string(session->in_buffer))){ ssh_set_error(session,SSH_FATAL,"No signature in packet"); return SSH_ERROR; } session->dh_server_signature=signature; dh_build_k(session); // send the MSG_NEWKEYS packet_clear_out(session); buffer_add_u8(session->out_buffer,SSH2_MSG_NEWKEYS); packet_send(session); session->dh_handshake_state=DH_STATE_NEWKEYS_TO_SEND; case DH_STATE_NEWKEYS_TO_SEND: ret=packet_flush(session,0); if(ret != SSH_OK) return ret; ssh_say(2,"SSH_MSG_NEWKEYS sent\n"); session->dh_handshake_state=DH_STATE_NEWKEYS_SENT; case DH_STATE_NEWKEYS_SENT: ret=packet_wait(session,SSH2_MSG_NEWKEYS,1); if(ret != SSH_OK) return ret; ssh_say(2,"Got SSH_MSG_NEWKEYS\n"); make_sessionid(session); /* set the cryptographic functions for the next crypto */ /* (it is needed for generate_session_keys for key lenghts) */ if(crypt_set_algorithms(session)) return SSH_ERROR; generate_session_keys(session); /* verify the host's signature. XXX do it sooner */ signature=session->dh_server_signature; session->dh_server_signature=NULL; if(signature_verify(session,signature)){ free(signature); return SSH_ERROR; } free(signature); /* forget it for now ... */ /* once we got SSH2_MSG_NEWKEYS we can switch next_crypto and current_crypto */ if(session->current_crypto) crypto_free(session->current_crypto); /* XXX later, include a function to change keys */ session->current_crypto=session->next_crypto; session->next_crypto=crypto_new(); session->dh_handshake_state=DH_STATE_FINISHED; return SSH_OK; default: ssh_set_error(session,SSH_FATAL,"Invalid state in dh_handshake():%d",session->dh_handshake_state); return SSH_ERROR; } /* not reached */ return SSH_ERROR; }