void svl_crypto_ctx_free(svl_crypto_ctx *ctx) { if (!ctx) return; if (ctx->keyring_file && ctx->keyring_file != keyring) keyring_free(ctx->keyring_file); h_free(ctx); }
int cmd_serval_sign(const char *sid_str, const size_t sid_len, const unsigned char *msg, const size_t msg_len, char *sig_str_buf, const size_t sig_str_size, const char *keyring_path, const size_t keyring_len) { int ret = 0; unsigned char signed_msg[msg_len + SIGNATURE_BYTES]; keyring_file *_keyring = NULL; unsigned char *key = NULL; unsigned char packedSid[SID_SIZE] = {0}; CHECK(sig_str_size >= 2*SIGNATURE_BYTES + 1,"Signature buffer too small"); if (sid_str) { CHECK_ERR(sid_len == 2*SID_SIZE && str_is_subscriber_id(sid_str) == 1,"Invalid SID"); stowSid(packedSid,0,sid_str); } if (keyring_path) { CHECK_ERR(serval_init_keyring(sid_str ? packedSid : NULL, sid_str ? SID_SIZE : 0, keyring_path, keyring_len, &_keyring, &key, NULL), "Failed to initialize Serval keyring"); } else { CHECK_ERR(serval_extract_sas(&key,NULL,keyring,packedSid),"Failed to fetch SAS key"); } CHECK_ERR(serval_create_signature(key, msg, msg_len, signed_msg, SIGNATURE_BYTES + msg_len),"Failed to create signature"); strncpy(sig_str_buf,alloca_tohex(signed_msg + msg_len,SIGNATURE_BYTES),2*SIGNATURE_BYTES); sig_str_buf[2*SIGNATURE_BYTES] = '\0'; ret = 1; error: if (_keyring) keyring_free(_keyring); return ret; }
int serval_sign(const char *sid, const size_t sid_len, const unsigned char *msg, const size_t msg_len, char *sig_buffer, const size_t sig_size, const char *keyringName, const size_t keyring_len) { keyring_identity *new_ident; char keyringFile[1024]; assert(msg_len); if (sid) assert(sid_len == 2*SID_SIZE); if (keyringName == NULL || keyring_len == 0) { FORM_SERVAL_INSTANCE_PATH(keyringFile, "serval.keyring"); // if no keyring specified, use default keyring } else { // otherwise, use specified keyring (NOTE: if keyring does not exist, it will be created) strncpy(keyringFile,keyringName,keyring_len); keyringFile[keyring_len] = '\0'; } keyring = keyring_open(keyringFile); keyring_enter_pin(keyring, KEYRING_PIN); // unlocks Serval keyring for using identities (also initializes global default identity my_subscriber) if (!sid) { //create new sid int c; for(c=0;c<keyring->context_count;c++) { // cycle through the keyring contexts until we find one with room for another identity new_ident = keyring_create_identity(keyring,keyring->contexts[c], KEYRING_PIN); // create new Serval identity if (new_ident) break; } if (!new_ident) { fprintf(stderr, "failed to create new SID\n"); return 1; } if (keyring_commit(keyring)) { // need to commit keyring or else new identity won't be saved (needs root permissions) fprintf(stderr, "Failed to save new SID into keyring...make sure you are running as root!\n"); return 1; } sid = alloca_tohex_sid(new_ident->subscriber->sid); // convert SID from binary to hex } else { if (!str_is_subscriber_id(sid)) { fprintf(stderr,"Invalid SID\n"); return 1; } } unsigned char packedSid[SID_SIZE]; stowSid(packedSid,0,sid); unsigned char *key=keyring_find_sas_private(keyring, packedSid, NULL); // get SAS key associated with our SID if (!key) return 1; unsigned char hash[crypto_hash_sha512_BYTES]; unsigned long long sig_length = SIGNATURE_BYTES; crypto_hash_sha512(hash, msg, msg_len); // create sha512 hash of message, which will then be signed unsigned char signed_msg[msg_len + sig_length]; memcpy(signed_msg,msg,msg_len); int ret = crypto_create_signature(key, hash, crypto_hash_sha512_BYTES, &signed_msg[msg_len], &sig_length); // create signature of message hash, append it to end of message if (!ret) { //success printf("%s\n", alloca_tohex(signed_msg + msg_len, sig_length)); printf("%s\n",sid); if (sig_size > 0) { if (sig_size >= 2*sig_length + 1) { strncpy(sig_buffer,alloca_tohex(signed_msg + msg_len,sig_length),2*sig_length); sig_buffer[2*sig_length] = '\0'; } else fprintf(stderr,"Insufficient signature buffer size\n"); } } keyring_free(keyring); return ret; }
/* Open keyring file, read BAM and create initial context using the stored salt. */ keyring_file *keyring_open(char *file) { /* Allocate structure */ keyring_file *k=calloc(sizeof(keyring_file),1); if (!k) { WHY_perror("calloc"); return NULL; } /* Open keyring file read-write if we can, else use it read-only */ k->file=fopen(file,"r+"); if (!k->file) k->file=fopen(file,"r"); if (!k->file) k->file=fopen(file,"w+"); if (!k->file) { WHY_perror("fopen"); WHYF("Could not open keyring file %s", file); keyring_free(k); return NULL; } if (fseeko(k->file,0,SEEK_END)) { WHY_perror("fseeko"); WHYF("Could not seek to end of keyring file %s", file); keyring_free(k); return NULL; } k->file_size=ftello(k->file); if (k->file_size<KEYRING_PAGE_SIZE) { /* Uninitialised, so write 2KB of zeroes, followed by 2KB of random bytes as salt. */ if (fseeko(k->file,0,SEEK_SET)) { WHY_perror("fseeko"); WHYF("Could not seek to start of keyring file %s", file); keyring_free(k); return NULL; } unsigned char buffer[KEYRING_PAGE_SIZE]; bzero(&buffer[0],KEYRING_BAM_BYTES); if (fwrite(&buffer[0],2048,1,k->file)!=1) { WHY_perror("fwrite"); WHYF("Could not write empty bitmap in fresh keyring file %s", file); keyring_free(k); return NULL; } if (urandombytes(&buffer[0],KEYRING_PAGE_SIZE-KEYRING_BAM_BYTES)) { WHYF("Could not get random keyring salt to put in fresh keyring file %s", file); keyring_free(k); return NULL; } if (fwrite(&buffer[0],KEYRING_PAGE_SIZE-KEYRING_BAM_BYTES,1,k->file) != 1) { WHY_perror("fwrite"); WHYF("Could not write keyring salt in fresh keyring file %s", file); keyring_free(k); return NULL; } k->file_size=KEYRING_PAGE_SIZE; } /* Read BAMs for each slab in the file */ keyring_bam **b=&k->bam; off_t offset=0; while(offset<k->file_size) { /* Read bitmap from slab. Also, if offset is zero, read the salt */ if (fseeko(k->file,offset,SEEK_SET)) { WHY_perror("fseeko"); WHYF("Could not seek to BAM in keyring file %s", file); keyring_free(k); return NULL; } *b=calloc(sizeof(keyring_bam),1); if (!(*b)) { WHY_perror("calloc"); WHYF("Could not allocate keyring_bam structure for key ring file %s", file); keyring_free(k); return NULL; } (*b)->file_offset=offset; /* Read bitmap */ int r=fread(&(*b)->bitmap[0],KEYRING_BAM_BYTES,1,k->file); if (r!=1) { WHY_perror("fread"); WHYF("Could not read BAM from keyring file %s", file); keyring_free(k); return NULL; } /* Read salt if this is the first bitmap block. We setup a context for this self-supplied key-ring salt. (other keyring salts may be provided later on, resulting in multiple contexts being loaded) */ if (!offset) { k->contexts[0]=calloc(sizeof(keyring_context),1); if (!k->contexts[0]) { WHY_perror("calloc"); WHYF("Could not allocate keyring_context for keyring file %s", file); keyring_free(k); return NULL; } k->contexts[0]->KeyRingPin=strdup(""); /* Implied empty PIN if none provided */ k->contexts[0]->KeyRingSaltLen=KEYRING_PAGE_SIZE-KEYRING_BAM_BYTES; k->contexts[0]->KeyRingSalt=malloc(k->contexts[0]->KeyRingSaltLen); if (!k->contexts[0]->KeyRingSalt) { WHY_perror("malloc"); WHYF("Could not allocate keyring_context->salt for keyring file %s", file); keyring_free(k); return NULL; } r=fread(&k->contexts[0]->KeyRingSalt[0],k->contexts[0]->KeyRingSaltLen,1,k->file); if (r!=1) { WHY_perror("fread"); WHYF("Could not read salt from keyring file %s", file); keyring_free(k); return NULL; } k->context_count=1; } /* Skip to next slab, and find next bam pointer. */ offset+=KEYRING_PAGE_SIZE*(KEYRING_BAM_BYTES<<3); b=&(*b)->next; } return k; }