int _libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx, const unsigned char *hash, unsigned long hash_len, unsigned char *sig) { unsigned char zhash[SHA_DIGEST_LENGTH + 1]; gcry_sexp_t sig_sexp; gcry_sexp_t data; int ret; const char *tmp; size_t size; if (hash_len != SHA_DIGEST_LENGTH) { return -1; } memcpy(zhash + 1, hash, hash_len); zhash[0] = 0; if (gcry_sexp_build(&data, NULL, "(data (value %b))", hash_len + 1, zhash)) { return -1; } ret = gcry_pk_sign(&sig_sexp, data, dsactx); gcry_sexp_release(data); if (ret != 0) { return -1; } memset(sig, 0, 40); /* Extract R. */ data = gcry_sexp_find_token(sig_sexp, "r", 0); if (!data) goto err; tmp = gcry_sexp_nth_data(data, 1, &size); if (!tmp) goto err; if (tmp[0] == '\0') { tmp++; size--; } if (size < 1 || size > 20) goto err; memcpy(sig + (20 - size), tmp, size); gcry_sexp_release(data); /* Extract S. */ data = gcry_sexp_find_token(sig_sexp, "s", 0); if (!data) goto err; tmp = gcry_sexp_nth_data(data, 1, &size); if (!tmp) goto err; if (tmp[0] == '\0') { tmp++; size--; } if (size < 1 || size > 20) goto err; memcpy(sig + 20 + (20 - size), tmp, size); goto out; err: ret = -1; out: if (sig_sexp) { gcry_sexp_release(sig_sexp); } if (data) { gcry_sexp_release(data); } return ret; }
static int rsa_public_to_string(gcry_sexp_t key, ssh_buffer buffer) { #elif defined HAVE_LIBCRYPTO static int rsa_public_to_string(RSA *key, ssh_buffer buffer) { #endif ssh_string e = NULL; ssh_string n = NULL; int rc = -1; #ifdef HAVE_LIBGCRYPT const char *tmp; size_t size; gcry_sexp_t sexp; sexp = gcry_sexp_find_token(key, "n", 0); if (sexp == NULL) { goto error; } tmp = gcry_sexp_nth_data(sexp, 1, &size); n = string_new(size); if (n == NULL) { goto error; } string_fill(n, (char *) tmp, size); gcry_sexp_release(sexp); sexp = gcry_sexp_find_token(key, "e", 0); if (sexp == NULL) { goto error; } tmp = gcry_sexp_nth_data(sexp, 1, &size); e = string_new(size); if (e == NULL) { goto error; } string_fill(e, (char *) tmp, size); #elif defined HAVE_LIBCRYPTO e = make_bignum_string(key->e); n = make_bignum_string(key->n); if (e == NULL || n == NULL) { goto error; } #endif if (buffer_add_ssh_string(buffer, e) < 0) { goto error; } if (buffer_add_ssh_string(buffer, n) < 0) { goto error; } rc = 0; error: #ifdef HAVE_LIBGCRYPT gcry_sexp_release(sexp); #endif string_burn(e); string_free(e); string_burn(n); string_free(n); return rc; }
/* Signature decoding functions */ static ssh_string signature_to_string(SIGNATURE *sign) { unsigned char buffer[40] = {0}; ssh_buffer tmpbuf = NULL; ssh_string str = NULL; ssh_string tmp = NULL; ssh_string rs = NULL; int rc = -1; #ifdef HAVE_LIBGCRYPT const char *r = NULL; const char *s = NULL; gcry_sexp_t sexp; size_t size = 0; #elif defined HAVE_LIBCRYPTO ssh_string r = NULL; ssh_string s = NULL; #endif tmpbuf = buffer_new(); if (tmpbuf == NULL) { return NULL; } tmp = string_from_char(ssh_type_to_char(sign->type)); if (tmp == NULL) { buffer_free(tmpbuf); return NULL; } if (buffer_add_ssh_string(tmpbuf, tmp) < 0) { buffer_free(tmpbuf); string_free(tmp); return NULL; } string_free(tmp); switch(sign->type) { case TYPE_DSS: #ifdef HAVE_LIBGCRYPT sexp = gcry_sexp_find_token(sign->dsa_sign, "r", 0); if (sexp == NULL) { buffer_free(tmpbuf); return NULL; } r = gcry_sexp_nth_data(sexp, 1, &size); if (*r == 0) { /* libgcrypt put 0 when first bit is set */ size--; r++; } memcpy(buffer, r + size - 20, 20); gcry_sexp_release(sexp); sexp = gcry_sexp_find_token(sign->dsa_sign, "s", 0); if (sexp == NULL) { buffer_free(tmpbuf); return NULL; } s = gcry_sexp_nth_data(sexp,1,&size); if (*s == 0) { size--; s++; } memcpy(buffer+ 20, s + size - 20, 20); gcry_sexp_release(sexp); #elif defined HAVE_LIBCRYPTO r = make_bignum_string(sign->dsa_sign->r); if (r == NULL) { buffer_free(tmpbuf); return NULL; } s = make_bignum_string(sign->dsa_sign->s); if (s == NULL) { buffer_free(tmpbuf); string_free(r); return NULL; } memcpy(buffer, (char *)string_data(r) + string_len(r) - 20, 20); memcpy(buffer + 20, (char *)string_data(s) + string_len(s) - 20, 20); string_free(r); string_free(s); #endif /* HAVE_LIBCRYPTO */ rs = string_new(40); if (rs == NULL) { buffer_free(tmpbuf); return NULL; } string_fill(rs, buffer, 40); rc = buffer_add_ssh_string(tmpbuf, rs); string_free(rs); if (rc < 0) { buffer_free(tmpbuf); return NULL; } break; case TYPE_RSA: case TYPE_RSA1: #ifdef HAVE_LIBGCRYPT sexp = gcry_sexp_find_token(sign->rsa_sign, "s", 0); if (sexp == NULL) { buffer_free(tmpbuf); return NULL; } s = gcry_sexp_nth_data(sexp,1,&size); if (*s == 0) { size--; s++; } rs = string_new(size); if (rs == NULL) { buffer_free(tmpbuf); return NULL; } string_fill(rs, (char *) s, size); rc = buffer_add_ssh_string(tmpbuf, rs); gcry_sexp_release(sexp); string_free(rs); if (rc < 0) { buffer_free(tmpbuf); return NULL; } #elif defined HAVE_LIBCRYPTO if (buffer_add_ssh_string(tmpbuf,sign->rsa_sign) < 0) { buffer_free(tmpbuf); return NULL; } #endif break; } str = string_new(buffer_get_len(tmpbuf)); if (str == NULL) { buffer_free(tmpbuf); return NULL; } string_fill(str, buffer_get(tmpbuf), buffer_get_len(tmpbuf)); buffer_free(tmpbuf); return str; }
/** \brief Makes a PUBLIC_KEY object out of a PRIVATE_KEY object * \param prv the Private key * \returns the public key * \see publickey_to_string() */ ssh_public_key publickey_from_privatekey(ssh_private_key prv) { ssh_public_key key = NULL; #ifdef HAVE_LIBGCRYPT gcry_sexp_t sexp; const char *tmp = NULL; size_t size; ssh_string p = NULL; ssh_string q = NULL; ssh_string g = NULL; ssh_string y = NULL; ssh_string e = NULL; ssh_string n = NULL; #endif /* HAVE_LIBGCRYPT */ key = malloc(sizeof(struct ssh_public_key_struct)); if (key == NULL) { return NULL; } key->type = prv->type; switch(key->type) { case TYPE_DSS: #ifdef HAVE_LIBGCRYPT sexp = gcry_sexp_find_token(prv->dsa_priv, "p", 0); if (sexp == NULL) { goto error; } tmp = gcry_sexp_nth_data(sexp, 1, &size); p = string_new(size); if (p == NULL) { goto error; } string_fill(p,(char *) tmp, size); gcry_sexp_release(sexp); sexp = gcry_sexp_find_token(prv->dsa_priv,"q",0); if (sexp == NULL) { goto error; } tmp = gcry_sexp_nth_data(sexp,1,&size); q = string_new(size); if (q == NULL) { goto error; } string_fill(q,(char *) tmp,size); gcry_sexp_release(sexp); sexp = gcry_sexp_find_token(prv->dsa_priv, "g", 0); if (sexp == NULL) { goto error; } tmp = gcry_sexp_nth_data(sexp,1,&size); g = string_new(size); if (g == NULL) { goto error; } string_fill(g,(char *) tmp,size); gcry_sexp_release(sexp); sexp = gcry_sexp_find_token(prv->dsa_priv,"y",0); if (sexp == NULL) { goto error; } tmp = gcry_sexp_nth_data(sexp,1,&size); y = string_new(size); if (y == NULL) { goto error; } string_fill(y,(char *) tmp,size); gcry_sexp_release(sexp); gcry_sexp_build(&key->dsa_pub, NULL, "(public-key(dsa(p %b)(q %b)(g %b)(y %b)))", string_len(p), string_data(p), string_len(q), string_data(q), string_len(g), string_data(g), string_len(y), string_data(y)); string_burn(p); string_free(p); string_burn(q); string_free(q); string_burn(g); string_free(g); string_burn(y); string_free(y); #elif defined HAVE_LIBCRYPTO key->dsa_pub = DSA_new(); if (key->dsa_pub == NULL) { goto error; } key->dsa_pub->p = BN_dup(prv->dsa_priv->p); key->dsa_pub->q = BN_dup(prv->dsa_priv->q); key->dsa_pub->g = BN_dup(prv->dsa_priv->g); key->dsa_pub->pub_key = BN_dup(prv->dsa_priv->pub_key); if (key->dsa_pub->p == NULL || key->dsa_pub->q == NULL || key->dsa_pub->g == NULL || key->dsa_pub->pub_key == NULL) { goto error; } #endif /* HAVE_LIBCRYPTO */ break; case TYPE_RSA: case TYPE_RSA1: #ifdef HAVE_LIBGCRYPT sexp = gcry_sexp_find_token(prv->rsa_priv, "n", 0); if (sexp == NULL) { goto error; } tmp = gcry_sexp_nth_data(sexp, 1, &size); n = string_new(size); if (n == NULL) { goto error; } string_fill(n, (char *) tmp, size); gcry_sexp_release(sexp); sexp = gcry_sexp_find_token(prv->rsa_priv, "e", 0); if (sexp == NULL) { goto error; } tmp = gcry_sexp_nth_data(sexp, 1, &size); e = string_new(size); if (e == NULL) { goto error; } string_fill(e, (char *) tmp, size); gcry_sexp_release(sexp); gcry_sexp_build(&key->rsa_pub, NULL, "(public-key(rsa(n %b)(e %b)))", string_len(n), string_data(n), string_len(e), string_data(e)); if (key->rsa_pub == NULL) { goto error; } string_burn(e); string_free(e); string_burn(n); string_free(n); #elif defined HAVE_LIBCRYPTO key->rsa_pub = RSA_new(); if (key->rsa_pub == NULL) { goto error; } key->rsa_pub->e = BN_dup(prv->rsa_priv->e); key->rsa_pub->n = BN_dup(prv->rsa_priv->n); if (key->rsa_pub->e == NULL || key->rsa_pub->n == NULL) { goto error; } #endif break; } key->type_c = ssh_type_to_char(prv->type); return key; error: #ifdef HAVE_LIBGCRYPT gcry_sexp_release(sexp); string_burn(p); string_free(p); string_burn(q); string_free(q); string_burn(g); string_free(g); string_burn(y); string_free(y); string_burn(e); string_free(e); string_burn(n); string_free(n); #endif publickey_free(key); return NULL; }
static int dsa_public_to_string(gcry_sexp_t key, ssh_buffer buffer) { #elif defined HAVE_LIBCRYPTO static int dsa_public_to_string(DSA *key, ssh_buffer buffer) { #endif ssh_string p = NULL; ssh_string q = NULL; ssh_string g = NULL; ssh_string n = NULL; int rc = -1; #ifdef HAVE_LIBGCRYPT const char *tmp = NULL; size_t size; gcry_sexp_t sexp; sexp = gcry_sexp_find_token(key, "p", 0); if (sexp == NULL) { goto error; } tmp = gcry_sexp_nth_data(sexp, 1, &size); p = string_new(size); if (p == NULL) { goto error; } string_fill(p, (char *) tmp, size); gcry_sexp_release(sexp); sexp = gcry_sexp_find_token(key, "q", 0); if (sexp == NULL) { goto error; } tmp = gcry_sexp_nth_data(sexp, 1, &size); q = string_new(size); if (q == NULL) { goto error; } string_fill(q, (char *) tmp, size); gcry_sexp_release(sexp); sexp = gcry_sexp_find_token(key, "g", 0); if (sexp == NULL) { goto error; } tmp = gcry_sexp_nth_data(sexp, 1, &size); g = string_new(size); if (g == NULL) { goto error; } string_fill(g, (char *) tmp, size); gcry_sexp_release(sexp); sexp = gcry_sexp_find_token(key, "y", 0); if (sexp == NULL) { goto error; } tmp = gcry_sexp_nth_data(sexp, 1, &size); n = string_new(size); if (n == NULL) { goto error; } string_fill(n, (char *) tmp, size); #elif defined HAVE_LIBCRYPTO p = make_bignum_string(key->p); q = make_bignum_string(key->q); g = make_bignum_string(key->g); n = make_bignum_string(key->pub_key); if (p == NULL || q == NULL || g == NULL || n == NULL) { goto error; } #endif /* HAVE_LIBCRYPTO */ if (buffer_add_ssh_string(buffer, p) < 0) { goto error; } if (buffer_add_ssh_string(buffer, q) < 0) { goto error; } if (buffer_add_ssh_string(buffer, g) < 0) { goto error; } if (buffer_add_ssh_string(buffer, n) < 0) { goto error; } rc = 0; error: #ifdef HAVE_LIBGCRYPT gcry_sexp_release(sexp); #endif string_burn(p); string_free(p); string_burn(q); string_free(q); string_burn(g); string_free(g); string_burn(n); string_free(n); return rc; }
/* Read a sets of private DSA keys from a FILE* into the given * OtrlUserState. The FILE* must be open for reading. */ gcry_error_t otrl_privkey_read_FILEp(OtrlUserState us, FILE *privf) { int privfd; struct stat st; char *buf; const char *token; size_t tokenlen; gcry_error_t err; gcry_sexp_t allkeys; size_t i; if (!privf) return gcry_error(GPG_ERR_NO_ERROR); /* Release any old ideas we had about our keys */ otrl_privkey_forget_all(us); /* Load the data into a buffer */ privfd = fileno(privf); if (fstat(privfd, &st)) { err = gcry_error_from_errno(errno); return err; } buf = malloc(st.st_size); if (!buf && st.st_size > 0) { return gcry_error(GPG_ERR_ENOMEM); } if (fread(buf, st.st_size, 1, privf) != 1) { err = gcry_error_from_errno(errno); free(buf); return err; } err = gcry_sexp_new(&allkeys, buf, st.st_size, 0); free(buf); if (err) { return err; } token = gcry_sexp_nth_data(allkeys, 0, &tokenlen); if (tokenlen != 8 || strncmp(token, "privkeys", 8)) { gcry_sexp_release(allkeys); return gcry_error(GPG_ERR_UNUSABLE_SECKEY); } /* Get each account */ for(i=1; i<gcry_sexp_length(allkeys); ++i) { gcry_sexp_t names, protos, privs; char *name, *proto; gcry_sexp_t accounts; OtrlPrivKey *p; /* Get the ith "account" S-exp */ accounts = gcry_sexp_nth(allkeys, i); /* It's really an "account" S-exp? */ token = gcry_sexp_nth_data(accounts, 0, &tokenlen); if (tokenlen != 7 || strncmp(token, "account", 7)) { gcry_sexp_release(accounts); gcry_sexp_release(allkeys); return gcry_error(GPG_ERR_UNUSABLE_SECKEY); } /* Extract the name, protocol, and privkey S-exps */ names = gcry_sexp_find_token(accounts, "name", 0); protos = gcry_sexp_find_token(accounts, "protocol", 0); privs = gcry_sexp_find_token(accounts, "private-key", 0); gcry_sexp_release(accounts); if (!names || !protos || !privs) { gcry_sexp_release(names); gcry_sexp_release(protos); gcry_sexp_release(privs); gcry_sexp_release(allkeys); return gcry_error(GPG_ERR_UNUSABLE_SECKEY); } /* Extract the actual name and protocol */ token = gcry_sexp_nth_data(names, 1, &tokenlen); if (!token) { gcry_sexp_release(names); gcry_sexp_release(protos); gcry_sexp_release(privs); gcry_sexp_release(allkeys); return gcry_error(GPG_ERR_UNUSABLE_SECKEY); } name = malloc(tokenlen + 1); if (!name) { gcry_sexp_release(names); gcry_sexp_release(protos); gcry_sexp_release(privs); gcry_sexp_release(allkeys); return gcry_error(GPG_ERR_ENOMEM); } memmove(name, token, tokenlen); name[tokenlen] = '\0'; gcry_sexp_release(names); token = gcry_sexp_nth_data(protos, 1, &tokenlen); if (!token) { free(name); gcry_sexp_release(protos); gcry_sexp_release(privs); gcry_sexp_release(allkeys); return gcry_error(GPG_ERR_UNUSABLE_SECKEY); } proto = malloc(tokenlen + 1); if (!proto) { free(name); gcry_sexp_release(protos); gcry_sexp_release(privs); gcry_sexp_release(allkeys); return gcry_error(GPG_ERR_ENOMEM); } memmove(proto, token, tokenlen); proto[tokenlen] = '\0'; gcry_sexp_release(protos); /* Make a new OtrlPrivKey entry */ p = malloc(sizeof(*p)); if (!p) { free(name); free(proto); gcry_sexp_release(privs); gcry_sexp_release(allkeys); return gcry_error(GPG_ERR_ENOMEM); } /* Fill it in and link it up */ p->accountname = name; p->protocol = proto; p->pubkey_type = OTRL_PUBKEY_TYPE_DSA; p->privkey = privs; p->next = us->privkey_root; if (p->next) { p->next->tous = &(p->next); } p->tous = &(us->privkey_root); us->privkey_root = p; err = make_pubkey(&(p->pubkey_data), &(p->pubkey_datalen), p->privkey); if (err) { gcry_sexp_release(allkeys); otrl_privkey_forget(p); return gcry_error(GPG_ERR_UNUSABLE_SECKEY); } } gcry_sexp_release(allkeys); return gcry_error(GPG_ERR_NO_ERROR); }
ssh_string ssh_encrypt_rsa1(ssh_session session, ssh_string data, ssh_public_key key) { ssh_string str = NULL; size_t len = string_len(data); size_t size = 0; #ifdef HAVE_LIBGCRYPT const char *tmp = NULL; gcry_sexp_t ret_sexp; gcry_sexp_t data_sexp; if (gcry_sexp_build(&data_sexp, NULL, "(data(flags pkcs1)(value %b))", len, string_data(data))) { ssh_set_error(session, SSH_FATAL, "RSA1 encrypt: libgcrypt error"); return NULL; } if (gcry_pk_encrypt(&ret_sexp, data_sexp, key->rsa_pub)) { gcry_sexp_release(data_sexp); ssh_set_error(session, SSH_FATAL, "RSA1 encrypt: libgcrypt error"); return NULL; } gcry_sexp_release(data_sexp); data_sexp = gcry_sexp_find_token(ret_sexp, "a", 0); if (data_sexp == NULL) { ssh_set_error(session, SSH_FATAL, "RSA1 encrypt: libgcrypt error"); gcry_sexp_release(ret_sexp); return NULL; } tmp = gcry_sexp_nth_data(data_sexp, 1, &size); if (*tmp == 0) { size--; tmp++; } str = string_new(size); if (str == NULL) { ssh_set_error(session, SSH_FATAL, "Not enough space"); gcry_sexp_release(data_sexp); gcry_sexp_release(ret_sexp); return NULL; } string_fill(str, tmp, size); gcry_sexp_release(data_sexp); gcry_sexp_release(ret_sexp); #elif defined HAVE_LIBCRYPTO size = RSA_size(key->rsa_pub); str = string_new(size); if (str == NULL) { ssh_set_error(session, SSH_FATAL, "Not enough space"); return NULL; } if (RSA_public_encrypt(len, string_data(data), string_data(str), key->rsa_pub, RSA_PKCS1_PADDING) < 0) { string_free(str); return NULL; } #endif return str; }
static gcry_mpi_t * sexp_to_kparms (gcry_sexp_t sexp, unsigned long *created) { gcry_sexp_t list, l2; const char *name; const char *s; size_t n; int i, idx; const char *elems; gcry_mpi_t *array; *created = 0; list = gcry_sexp_find_token (sexp, "private-key", 0 ); if(!list) return NULL; /* quick hack to get the creation time. */ l2 = gcry_sexp_find_token (list, "created", 0); if (l2 && (name = gcry_sexp_nth_data (l2, 1, &n))) { char *tmp = xmalloc (n+1); memcpy (tmp, name, n); tmp[n] = 0; *created = strtoul (tmp, NULL, 10); xfree (tmp); } gcry_sexp_release (l2); l2 = gcry_sexp_cadr (list); gcry_sexp_release (list); list = l2; name = gcry_sexp_nth_data (list, 0, &n); if(!name || n != 3 || memcmp (name, "rsa", 3)) { gcry_sexp_release (list); return NULL; } /* Parameter names used with RSA. */ elems = "nedpqu"; array = xcalloc (strlen(elems) + 1, sizeof *array); for (idx=0, s=elems; *s; s++, idx++ ) { l2 = gcry_sexp_find_token (list, s, 1); if (!l2) { for (i=0; i<idx; i++) gcry_mpi_release (array[i]); xfree (array); gcry_sexp_release (list); return NULL; /* required parameter not found */ } array[idx] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG); gcry_sexp_release (l2); if (!array[idx]) { for (i=0; i<idx; i++) gcry_mpi_release (array[i]); xfree (array); gcry_sexp_release (list); return NULL; /* required parameter is invalid */ } } gcry_sexp_release (list); return array; }
/* Return the secret key as an S-Exp in RESULT after locating it using the GRIP. Stores NULL at RESULT if the operation shall be diverted to a token; in this case an allocated S-expression with the shadow_info part from the file is stored at SHADOW_INFO. CACHE_MODE defines now the cache shall be used. DESC_TEXT may be set to present a custom description for the pinentry. LOOKUP_TTL is an optional function to convey a TTL to the cache manager; we do not simply pass the TTL value because the value is only needed if an unprotect action was needed and looking up the TTL may have some overhead (e.g. scanning the sshcontrol file). */ gpg_error_t agent_key_from_file (ctrl_t ctrl, const char *desc_text, const unsigned char *grip, unsigned char **shadow_info, cache_mode_t cache_mode, lookup_ttl_t lookup_ttl, gcry_sexp_t *result) { int rc; unsigned char *buf; size_t len, buflen, erroff; gcry_sexp_t s_skey; int got_shadow_info = 0; *result = NULL; if (shadow_info) *shadow_info = NULL; rc = read_key_file (grip, &s_skey); if (rc) return rc; /* For use with the protection functions we also need the key as an canonical encoded S-expression in a buffer. Create this buffer now. */ rc = make_canon_sexp (s_skey, &buf, &len); if (rc) return rc; switch (agent_private_key_type (buf)) { case PRIVATE_KEY_CLEAR: break; /* no unprotection needed */ case PRIVATE_KEY_PROTECTED: { gcry_sexp_t comment_sexp; size_t comment_length; char *desc_text_final; const char *comment = NULL; /* Note, that we will take the comment as a C string for display purposes; i.e. all stuff beyond a Nul character is ignored. */ comment_sexp = gcry_sexp_find_token (s_skey, "comment", 0); if (comment_sexp) comment = gcry_sexp_nth_data (comment_sexp, 1, &comment_length); if (!comment) { comment = ""; comment_length = 0; } desc_text_final = NULL; if (desc_text) { if (comment[comment_length]) { /* Not a C-string; create one. We might here allocate more than actually displayed but well, that shouldn't be a problem. */ char *tmp = xtrymalloc (comment_length+1); if (!tmp) rc = gpg_error_from_syserror (); else { memcpy (tmp, comment, comment_length); tmp[comment_length] = 0; rc = modify_description (desc_text, tmp, &desc_text_final); xfree (tmp); } } else rc = modify_description (desc_text, comment, &desc_text_final); } if (!rc) { rc = unprotect (ctrl, desc_text_final, &buf, grip, cache_mode, lookup_ttl); if (rc) log_error ("failed to unprotect the secret key: %s\n", gpg_strerror (rc)); } gcry_sexp_release (comment_sexp); xfree (desc_text_final); } break; case PRIVATE_KEY_SHADOWED: if (shadow_info) { const unsigned char *s; size_t n; rc = agent_get_shadow_info (buf, &s); if (!rc) { n = gcry_sexp_canon_len (s, 0, NULL,NULL); assert (n); *shadow_info = xtrymalloc (n); if (!*shadow_info) rc = out_of_core (); else { memcpy (*shadow_info, s, n); rc = 0; got_shadow_info = 1; } } if (rc) log_error ("get_shadow_info failed: %s\n", gpg_strerror (rc)); } else rc = gpg_error (GPG_ERR_UNUSABLE_SECKEY); break; default: log_error ("invalid private key format\n"); rc = gpg_error (GPG_ERR_BAD_SECKEY); break; } gcry_sexp_release (s_skey); s_skey = NULL; if (rc || got_shadow_info) { xfree (buf); return rc; } buflen = gcry_sexp_canon_len (buf, 0, NULL, NULL); rc = gcry_sexp_sscan (&s_skey, &erroff, (char*)buf, buflen); wipememory (buf, buflen); xfree (buf); if (rc) { log_error ("failed to build S-Exp (off=%u): %s\n", (unsigned int)erroff, gpg_strerror (rc)); return rc; } *result = s_skey; return 0; }
/* fixme: we need better tests */ static void basic (void) { int pass; gcry_sexp_t sexp; int idx; char *secure_buffer; size_t secure_buffer_len; const char *string; static struct { const char *token; const char *parm; } values[] = { { "public-key", NULL }, { "dsa", NULL }, { "dsa", "p" }, { "dsa", "y" }, { "dsa", "q" }, { "dsa", "g" }, { NULL } }; info ("doing some pretty pointless tests\n"); secure_buffer_len = 99; secure_buffer = gcry_xmalloc_secure (secure_buffer_len); memset (secure_buffer, 'G', secure_buffer_len); for (pass=0;;pass++) { switch (pass) { case 0: string = ("(public-key (dsa (p #41424344#) (y this_is_y) " "(q #61626364656667#) (g %m)))"); if ( gcry_sexp_build (&sexp, NULL, string, gcry_mpi_set_ui (NULL, 42)) ) { fail (" scanning `%s' failed\n", string); return; } break; case 1: string = ("(public-key (dsa (p #41424344#) (y this_is_y) " "(q %b) (g %m)))"); if ( gcry_sexp_build (&sexp, NULL, string, 15, "foo\0\x01\0x02789012345", gcry_mpi_set_ui (NULL, 42)) ) { fail (" scanning `%s' failed\n", string); return; } break; case 2: string = ("(public-key (dsa (p #41424344#) (y silly_y_value) " "(q %b) (g %m)))"); if ( gcry_sexp_build (&sexp, NULL, string, secure_buffer_len, secure_buffer, gcry_mpi_set_ui (NULL, 17)) ) { fail (" scanning `%s' failed\n", string); return; } if (!gcry_is_secure (sexp)) fail ("gcry_sexp_build did not switch to secure memory\n"); break; case 3: { gcry_sexp_t help_sexp; if (gcry_sexp_new (&help_sexp, "(foobar-parms (xp #1234#)(xq #03#))", 0, 1)) { fail (" scanning fixed string failed\n"); return; } string = ("(public-key (dsa (p #41424344#) (parm %S) " "(y dummy)(q %b) (g %m)))"); if ( gcry_sexp_build (&sexp, NULL, string, help_sexp, secure_buffer_len, secure_buffer, gcry_mpi_set_ui (NULL, 17)) ) { fail (" scanning `%s' failed\n", string); return; } gcry_sexp_release (help_sexp); } break; default: return; /* Ready. */ } /* now find something */ for (idx=0; values[idx].token; idx++) { const char *token = values[idx].token; const char *parm = values[idx].parm; gcry_sexp_t s1, s2; gcry_mpi_t a; const char *p; size_t n; s1 = gcry_sexp_find_token (sexp, token, strlen(token) ); if (!s1) { fail ("didn't found `%s'\n", token); continue; } p = gcry_sexp_nth_data (s1, 0, &n); if (!p) { fail ("no car for `%s'\n", token); continue; } info ("car=`%.*s'\n", (int)n, p); s2 = gcry_sexp_cdr (s1); if (!s2) { fail ("no cdr for `%s'\n", token); continue; } p = gcry_sexp_nth_data (s2, 0, &n); if (p) { fail ("data at car of `%s'\n", token); continue; } if (parm) { s2 = gcry_sexp_find_token (s1, parm, strlen (parm)); if (!s2) { fail ("didn't found `%s'\n", parm); continue; } p = gcry_sexp_nth_data (s2, 0, &n); if (!p) { fail("no car for `%s'\n", parm ); continue; } info ("car=`%.*s'\n", (int)n, p); p = gcry_sexp_nth_data (s2, 1, &n); if (!p) { fail("no cdr for `%s'\n", parm ); continue; } info ("cdr=`%.*s'\n", (int)n, p); a = gcry_sexp_nth_mpi (s2, 0, GCRYMPI_FMT_USG); if (!a) { fail("failed to cdr the mpi for `%s'\n", parm); continue; } } } gcry_sexp_release (sexp); sexp = NULL; } gcry_free (secure_buffer); }
/* Return the public key for the keygrip GRIP. The result is stored at RESULT. This function extracts the public key from the private key database. On failure an error code is returned and NULL stored at RESULT. */ gpg_error_t agent_public_key_from_file (ctrl_t ctrl, const unsigned char *grip, gcry_sexp_t *result) { gpg_error_t err; int i, idx; gcry_sexp_t s_skey; const char *algoname, *elems; int npkey; gcry_mpi_t array[10]; gcry_sexp_t curve = NULL; gcry_sexp_t flags = NULL; gcry_sexp_t uri_sexp, comment_sexp; const char *uri, *comment; size_t uri_length, comment_length; char *format, *p; void *args[2+7+2+2+1]; /* Size is 2 + max. # of elements + 2 for uri + 2 for comment + end-of-list. */ int argidx; gcry_sexp_t list = NULL; const char *s; (void)ctrl; *result = NULL; err = read_key_file (grip, &s_skey); if (err) return err; for (i=0; i < DIM (array); i++) array[i] = NULL; err = extract_private_key (s_skey, 0, &algoname, &npkey, NULL, &elems, array, DIM (array), &curve, &flags); if (err) { gcry_sexp_release (s_skey); return err; } uri = NULL; uri_length = 0; uri_sexp = gcry_sexp_find_token (s_skey, "uri", 0); if (uri_sexp) uri = gcry_sexp_nth_data (uri_sexp, 1, &uri_length); comment = NULL; comment_length = 0; comment_sexp = gcry_sexp_find_token (s_skey, "comment", 0); if (comment_sexp) comment = gcry_sexp_nth_data (comment_sexp, 1, &comment_length); gcry_sexp_release (s_skey); s_skey = NULL; /* FIXME: The following thing is pretty ugly code; we should investigate how to make it cleaner. Probably code to handle canonical S-expressions in a memory buffer is better suited for such a task. After all that is what we do in protect.c. Neeed to find common patterns and write a straightformward API to use them. */ assert (sizeof (size_t) <= sizeof (void*)); format = xtrymalloc (15+4+7*npkey+10+15+1+1); if (!format) { err = gpg_error_from_syserror (); for (i=0; array[i]; i++) gcry_mpi_release (array[i]); gcry_sexp_release (curve); gcry_sexp_release (flags); gcry_sexp_release (uri_sexp); gcry_sexp_release (comment_sexp); return err; } argidx = 0; p = stpcpy (stpcpy (format, "(public-key("), algoname); p = stpcpy (p, "%S%S"); /* curve name and flags. */ args[argidx++] = &curve; args[argidx++] = &flags; for (idx=0, s=elems; idx < npkey; idx++) { *p++ = '('; *p++ = *s++; p = stpcpy (p, " %m)"); assert (argidx < DIM (args)); args[argidx++] = &array[idx]; } *p++ = ')'; if (uri) { p = stpcpy (p, "(uri %b)"); assert (argidx+1 < DIM (args)); args[argidx++] = (void *)&uri_length; args[argidx++] = (void *)&uri; } if (comment) { p = stpcpy (p, "(comment %b)"); assert (argidx+1 < DIM (args)); args[argidx++] = (void *)&comment_length; args[argidx++] = (void*)&comment; } *p++ = ')'; *p = 0; assert (argidx < DIM (args)); args[argidx] = NULL; err = gcry_sexp_build_array (&list, NULL, format, args); xfree (format); for (i=0; array[i]; i++) gcry_mpi_release (array[i]); gcry_sexp_release (curve); gcry_sexp_release (flags); gcry_sexp_release (uri_sexp); gcry_sexp_release (comment_sexp); if (!err) *result = list; return err; }
/* Parse a private key S-expression and retutn a malloced array with the RSA paramaters in pkcs#12 order. The caller needs to deep-release this array. */ static gcry_mpi_t * sexp_to_kparms (gcry_sexp_t sexp) { gcry_sexp_t list, l2; const char *name; const char *s; size_t n; int idx; const char *elems; gcry_mpi_t *array; list = gcry_sexp_find_token (sexp, "private-key", 0 ); if(!list) return NULL; l2 = gcry_sexp_cadr (list); gcry_sexp_release (list); list = l2; name = gcry_sexp_nth_data (list, 0, &n); if(!name || n != 3 || memcmp (name, "rsa", 3)) { gcry_sexp_release (list); return NULL; } /* Parameter names used with RSA in the pkcs#12 order. */ elems = "nedqp--u"; array = xtrycalloc (strlen(elems) + 1, sizeof *array); if (!array) { gcry_sexp_release (list); return NULL; } for (idx=0, s=elems; *s; s++, idx++ ) { if (*s == '-') continue; /* Computed below */ l2 = gcry_sexp_find_token (list, s, 1); if (l2) { array[idx] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG); gcry_sexp_release (l2); } if (!array[idx]) /* Required parameter not found or invalid. */ { for (idx=0; array[idx]; idx++) gcry_mpi_release (array[idx]); xfree (array); gcry_sexp_release (list); return NULL; } } gcry_sexp_release (list); array[5] = gcry_mpi_snew (0); /* compute d mod (q-1) */ gcry_mpi_sub_ui (array[5], array[3], 1); gcry_mpi_mod (array[5], array[2], array[5]); array[6] = gcry_mpi_snew (0); /* compute d mod (p-1) */ gcry_mpi_sub_ui (array[6], array[4], 1); gcry_mpi_mod (array[6], array[3], array[6]); return array; }
STRING *signature_to_string(SIGNATURE *sign){ STRING *str; STRING *rs; #ifdef HAVE_LIBGCRYPT const char *r,*s; gcry_sexp_t sexp; size_t size; #elif defined HAVE_LIBCRYPTO STRING *r,*s; #endif unsigned char buffer[40]; BUFFER *tmpbuf=buffer_new(); STRING *tmp; tmp=string_from_char(ssh_type_to_char(sign->type)); buffer_add_ssh_string(tmpbuf,tmp); free(tmp); switch(sign->type){ case TYPE_DSS: memset(buffer,0,40); #ifdef HAVE_LIBGCRYPT sexp=gcry_sexp_find_token(sign->dsa_sign,"r",0); r=gcry_sexp_nth_data(sexp,1,&size); if (*r == 0) /* libgcrypt put 0 when first bit is set */ { size--; r++; } memcpy(buffer,r + size - 20,20); gcry_sexp_release(sexp); sexp=gcry_sexp_find_token(sign->dsa_sign,"s",0); s=gcry_sexp_nth_data(sexp,1,&size); if (*s == 0) { size--; s++; } memcpy(buffer+ 20, s + size - 20, 20); gcry_sexp_release(sexp); #elif defined HAVE_LIBCRYPTO r=make_bignum_string(sign->dsa_sign->r); s=make_bignum_string(sign->dsa_sign->s); rs=string_new(40); memcpy(buffer,r->string+string_len(r)-20,20); memcpy(buffer+ 20, s->string + string_len(s) - 20, 20); free(r); free(s); #endif rs=string_new(40); string_fill(rs,buffer,40); buffer_add_ssh_string(tmpbuf,rs); free(rs); break; case TYPE_RSA: case TYPE_RSA1: #ifdef HAVE_LIBGCRYPT sexp=gcry_sexp_find_token(sign->rsa_sign,"s",0); s=gcry_sexp_nth_data(sexp,1,&size); if (*s == 0) { size--; s++; } rs=string_new(size); string_fill(rs,(char *)s,size); buffer_add_ssh_string(tmpbuf,rs); gcry_sexp_release(sexp); free(rs); #elif defined HAVE_LIBCRYPTO buffer_add_ssh_string(tmpbuf,sign->rsa_sign); #endif break; } str=string_new(buffer_get_len(tmpbuf)); string_fill(str,buffer_get(tmpbuf),buffer_get_len(tmpbuf)); buffer_free(tmpbuf); return str; }
PUBLIC_KEY *publickey_from_privatekey(PRIVATE_KEY *prv){ PUBLIC_KEY *key=malloc(sizeof(PUBLIC_KEY)); #ifdef HAVE_LIBGCRYPT gcry_sexp_t sexp; const char *tmp; size_t size; STRING *p,*q,*g,*y,*e,*n; #endif key->type=prv->type; switch(key->type){ case TYPE_DSS: #ifdef HAVE_LIBGCRYPT sexp=gcry_sexp_find_token(prv->dsa_priv,"p",0); tmp=gcry_sexp_nth_data(sexp,1,&size); p=string_new(size); string_fill(p,(char *)tmp,size); gcry_sexp_release(sexp); sexp=gcry_sexp_find_token(prv->dsa_priv,"q",0); tmp=gcry_sexp_nth_data(sexp,1,&size); q=string_new(size); string_fill(q,(char *)tmp,size); gcry_sexp_release(sexp); sexp=gcry_sexp_find_token(prv->dsa_priv,"g",0); tmp=gcry_sexp_nth_data(sexp,1,&size); g=string_new(size); string_fill(g,(char *)tmp,size); gcry_sexp_release(sexp); sexp=gcry_sexp_find_token(prv->dsa_priv,"y",0); tmp=gcry_sexp_nth_data(sexp,1,&size); y=string_new(size); string_fill(y,(char *)tmp,size); gcry_sexp_release(sexp); gcry_sexp_build(&key->dsa_pub,NULL,"(public-key(dsa(p %b)(q %b)(g %b)(y %b)))",string_len(p),p->string,string_len(q),q->string,string_len(g),g->string,string_len(y),y->string); free(p); free(q); free(g); free(y); #elif defined HAVE_LIBCRYPTO key->dsa_pub=DSA_new(); key->dsa_pub->p=BN_dup(prv->dsa_priv->p); key->dsa_pub->q=BN_dup(prv->dsa_priv->q); key->dsa_pub->pub_key=BN_dup(prv->dsa_priv->pub_key); key->dsa_pub->g=BN_dup(prv->dsa_priv->g); #endif break; case TYPE_RSA: case TYPE_RSA1: #ifdef HAVE_LIBGCRYPT sexp=gcry_sexp_find_token(prv->rsa_priv,"n",0); tmp=gcry_sexp_nth_data(sexp,1,&size); n=string_new(size); string_fill(n,(char *)tmp,size); gcry_sexp_release(sexp); sexp=gcry_sexp_find_token(prv->rsa_priv,"e",0); tmp=gcry_sexp_nth_data(sexp,1,&size); e=string_new(size); string_fill(e,(char *)tmp,size); gcry_sexp_release(sexp); gcry_sexp_build(&key->rsa_pub,NULL,"(public-key(rsa(n %b)(e %b)))",string_len(n),n->string,string_len(e),e->string); free(e); free(n); #elif defined HAVE_LIBCRYPTO key->rsa_pub=RSA_new(); key->rsa_pub->e=BN_dup(prv->rsa_priv->e); key->rsa_pub->n=BN_dup(prv->rsa_priv->n); #endif break; } key->type_c=ssh_type_to_char(prv->type); return key; }
/* Return the string name from the S-expression S_KEY as well as a string describing the names of the parameters. ALGONAMESIZE and ELEMSSIZE give the allocated size of the provided buffers. The buffers may be NULL if not required. If R_LIST is not NULL the top level list will be stored tehre; the caller needs to release it in this case. */ static gpg_error_t key_parms_from_sexp (gcry_sexp_t s_key, gcry_sexp_t *r_list, char *r_algoname, size_t algonamesize, char *r_elems, size_t elemssize) { gcry_sexp_t list, l2; const char *name, *algoname, *elems; size_t n; if (r_list) *r_list = NULL; list = gcry_sexp_find_token (s_key, "shadowed-private-key", 0 ); if (!list) list = gcry_sexp_find_token (s_key, "protected-private-key", 0 ); if (!list) list = gcry_sexp_find_token (s_key, "private-key", 0 ); if (!list) { log_error ("invalid private key format\n"); return gpg_error (GPG_ERR_BAD_SECKEY); } l2 = gcry_sexp_cadr (list); gcry_sexp_release (list); list = l2; name = gcry_sexp_nth_data (list, 0, &n); if (n==3 && !memcmp (name, "rsa", 3)) { algoname = "rsa"; elems = "ne"; } else if (n==3 && !memcmp (name, "dsa", 3)) { algoname = "dsa"; elems = "pqgy"; } else if (n==3 && !memcmp (name, "ecc", 3)) { algoname = "ecc"; elems = "pabgnq"; } else if (n==5 && !memcmp (name, "ecdsa", 5)) { algoname = "ecdsa"; elems = "pabgnq"; } else if (n==4 && !memcmp (name, "ecdh", 4)) { algoname = "ecdh"; elems = "pabgnq"; } else if (n==3 && !memcmp (name, "elg", 3)) { algoname = "elg"; elems = "pgy"; } else { log_error ("unknown private key algorithm\n"); gcry_sexp_release (list); return gpg_error (GPG_ERR_BAD_SECKEY); } if (r_algoname) { if (strlen (algoname) >= algonamesize) return gpg_error (GPG_ERR_BUFFER_TOO_SHORT); strcpy (r_algoname, algoname); } if (r_elems) { if (strlen (elems) >= elemssize) return gpg_error (GPG_ERR_BUFFER_TOO_SHORT); strcpy (r_elems, elems); } if (r_list) *r_list = list; else gcry_sexp_release (list); return 0; }
/* Return the Secure Shell type fingerprint for KEY using digest ALGO. The length of the fingerprint is returned at R_LEN and the fingerprint itself at R_FPR. In case of a error code is returned and NULL stored at R_FPR. */ static gpg_error_t get_fingerprint (gcry_sexp_t key, int algo, void **r_fpr, size_t *r_len, int as_string) { gpg_error_t err; gcry_sexp_t list = NULL; gcry_sexp_t l2 = NULL; const char *s; char *name = NULL; int idx; const char *elems; gcry_md_hd_t md = NULL; int blobmode = 0; *r_fpr = NULL; *r_len = 0; /* Check that the first element is valid. */ list = gcry_sexp_find_token (key, "public-key", 0); if (!list) list = gcry_sexp_find_token (key, "private-key", 0); if (!list) list = gcry_sexp_find_token (key, "protected-private-key", 0); if (!list) list = gcry_sexp_find_token (key, "shadowed-private-key", 0); if (!list) { err = gpg_err_make (default_errsource, GPG_ERR_UNKNOWN_SEXP); goto leave; } l2 = gcry_sexp_cadr (list); gcry_sexp_release (list); list = l2; l2 = NULL; name = gcry_sexp_nth_string (list, 0); if (!name) { err = gpg_err_make (default_errsource, GPG_ERR_INV_SEXP); goto leave; } err = gcry_md_open (&md, algo, 0); if (err) goto leave; switch (gcry_pk_map_name (name)) { case GCRY_PK_RSA: elems = "en"; gcry_md_write (md, "\0\0\0\x07ssh-rsa", 11); break; case GCRY_PK_DSA: elems = "pqgy"; gcry_md_write (md, "\0\0\0\x07ssh-dss", 11); break; case GCRY_PK_ECC: if (is_eddsa (list)) { elems = "q"; blobmode = 1; /* For now there is just one curve, thus no need to switch on it. */ gcry_md_write (md, "\0\0\0\x0b" "ssh-ed25519", 15); } else { /* We only support the 3 standard curves for now. It is just a quick hack. */ elems = "q"; gcry_md_write (md, "\0\0\0\x13" "ecdsa-sha2-nistp", 20); l2 = gcry_sexp_find_token (list, "curve", 0); if (!l2) elems = ""; else { gcry_free (name); name = gcry_sexp_nth_string (l2, 1); gcry_sexp_release (l2); l2 = NULL; if (!name) elems = ""; else if (!strcmp (name, "NIST P-256")||!strcmp (name, "nistp256")) gcry_md_write (md, "256\0\0\0\x08nistp256", 15); else if (!strcmp (name, "NIST P-384")||!strcmp (name, "nistp384")) gcry_md_write (md, "384\0\0\0\x08nistp384", 15); else if (!strcmp (name, "NIST P-521")||!strcmp (name, "nistp521")) gcry_md_write (md, "521\0\0\0\x08nistp521", 15); else elems = ""; } if (!*elems) err = gpg_err_make (default_errsource, GPG_ERR_UNKNOWN_CURVE); } break; default: elems = ""; err = gpg_err_make (default_errsource, GPG_ERR_PUBKEY_ALGO); break; } if (err) goto leave; for (idx = 0, s = elems; *s; s++, idx++) { l2 = gcry_sexp_find_token (list, s, 1); if (!l2) { err = gpg_err_make (default_errsource, GPG_ERR_INV_SEXP); goto leave; } if (blobmode) { const char *blob; size_t bloblen; unsigned char lenbuf[4]; blob = gcry_sexp_nth_data (l2, 1, &bloblen); if (!blob) { err = gpg_err_make (default_errsource, GPG_ERR_INV_SEXP); goto leave; } blob++; bloblen--; lenbuf[0] = bloblen >> 24; lenbuf[1] = bloblen >> 16; lenbuf[2] = bloblen >> 8; lenbuf[3] = bloblen; gcry_md_write (md, lenbuf, 4); gcry_md_write (md, blob, bloblen); } else { gcry_mpi_t a; unsigned char *buf; size_t buflen; a = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG); gcry_sexp_release (l2); l2 = NULL; if (!a) { err = gpg_err_make (default_errsource, GPG_ERR_INV_SEXP); goto leave; } err = gcry_mpi_aprint (GCRYMPI_FMT_SSH, &buf, &buflen, a); gcry_mpi_release (a); if (err) goto leave; gcry_md_write (md, buf, buflen); gcry_free (buf); } }
/* Return the public key for the keygrip GRIP. The result is stored at RESULT. This function extracts the public key from the private key database. On failure an error code is returned and NULL stored at RESULT. */ gpg_error_t agent_public_key_from_file (ctrl_t ctrl, const unsigned char *grip, gcry_sexp_t *result) { gpg_error_t err; int i, idx; gcry_sexp_t s_skey; char algoname[6]; char elems[7]; gcry_sexp_t uri_sexp, comment_sexp; const char *uri, *comment; size_t uri_length, comment_length; char *format, *p; void *args[4+2+2+1]; /* Size is max. # of elements + 2 for uri + 2 for comment + end-of-list. */ int argidx; gcry_sexp_t list, l2; const char *s; gcry_mpi_t *array; (void)ctrl; *result = NULL; err = read_key_file (grip, &s_skey); if (err) return err; err = key_parms_from_sexp (s_skey, &list, algoname, sizeof algoname, elems, sizeof elems); if (err) { gcry_sexp_release (s_skey); return err; } /* Allocate an array for the parameters and copy them out of the secret key. FIXME: We should have a generic copy function. */ array = xtrycalloc (strlen(elems) + 1, sizeof *array); if (!array) { err = gpg_error_from_syserror (); gcry_sexp_release (list); gcry_sexp_release (s_skey); return err; } for (idx=0, s=elems; *s; s++, idx++ ) { l2 = gcry_sexp_find_token (list, s, 1); if (!l2) { /* Required parameter not found. */ for (i=0; i<idx; i++) gcry_mpi_release (array[i]); xfree (array); gcry_sexp_release (list); gcry_sexp_release (s_skey); return gpg_error (GPG_ERR_BAD_SECKEY); } array[idx] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG); gcry_sexp_release (l2); if (!array[idx]) { /* Required parameter is invalid. */ for (i=0; i<idx; i++) gcry_mpi_release (array[i]); xfree (array); gcry_sexp_release (list); gcry_sexp_release (s_skey); return gpg_error (GPG_ERR_BAD_SECKEY); } } gcry_sexp_release (list); list = NULL; uri = NULL; uri_length = 0; uri_sexp = gcry_sexp_find_token (s_skey, "uri", 0); if (uri_sexp) uri = gcry_sexp_nth_data (uri_sexp, 1, &uri_length); comment = NULL; comment_length = 0; comment_sexp = gcry_sexp_find_token (s_skey, "comment", 0); if (comment_sexp) comment = gcry_sexp_nth_data (comment_sexp, 1, &comment_length); gcry_sexp_release (s_skey); s_skey = NULL; /* FIXME: The following thing is pretty ugly code; we should investigate how to make it cleaner. Probably code to handle canonical S-expressions in a memory buffer is better suited for such a task. After all that is what we do in protect.c. Neeed to find common patterns and write a straightformward API to use them. */ assert (sizeof (size_t) <= sizeof (void*)); format = xtrymalloc (15+7*strlen (elems)+10+15+1+1); if (!format) { err = gpg_error_from_syserror (); for (i=0; array[i]; i++) gcry_mpi_release (array[i]); xfree (array); gcry_sexp_release (uri_sexp); gcry_sexp_release (comment_sexp); return err; } argidx = 0; p = stpcpy (stpcpy (format, "(public-key("), algoname); for (idx=0, s=elems; *s; s++, idx++ ) { *p++ = '('; *p++ = *s; p = stpcpy (p, " %m)"); assert (argidx < DIM (args)); args[argidx++] = &array[idx]; } *p++ = ')'; if (uri) { p = stpcpy (p, "(uri %b)"); assert (argidx+1 < DIM (args)); args[argidx++] = (void *)&uri_length; args[argidx++] = (void *)&uri; } if (comment) { p = stpcpy (p, "(comment %b)"); assert (argidx+1 < DIM (args)); args[argidx++] = (void *)&comment_length; args[argidx++] = (void*)&comment; } *p++ = ')'; *p = 0; assert (argidx < DIM (args)); args[argidx] = NULL; err = gcry_sexp_build_array (&list, NULL, format, args); xfree (format); for (i=0; array[i]; i++) gcry_mpi_release (array[i]); xfree (array); gcry_sexp_release (uri_sexp); gcry_sexp_release (comment_sexp); if (!err) *result = list; return err; }
gcry_error_t jsapi_userstate_import_privkey(OtrlUserState us, char *accountname, char * protocol, gcry_mpi_t p, gcry_mpi_t q, gcry_mpi_t g, gcry_mpi_t y, gcry_mpi_t x){ size_t *erroff; const char *token; size_t tokenlen; gcry_error_t err; gcry_sexp_t allkeys; size_t i; //puts("jsapi_userstate_import_privkey: building sexp"); err = gcry_sexp_build(&allkeys,erroff,"(privkeys (account (name %s) (protocol %s) (private-key (dsa \ (p %M) (q %M) (g %M) (y %M) (x %M) ))))",accountname,protocol,p,q,g,y,x); if(err) return err; /* forget existing account/key */ OtrlPrivKey* existing_key = otrl_privkey_find(us,accountname,protocol); if( existing_key) otrl_privkey_forget(existing_key); //puts("getting allkeys from sexp"); token = gcry_sexp_nth_data(allkeys, 0, &tokenlen); if (tokenlen != 8 || strncmp(token, "privkeys", 8)) { gcry_sexp_release(allkeys); return gcry_error(GPG_ERR_UNUSABLE_SECKEY); } /* Get each account */ for(i=1; i<gcry_sexp_length(allkeys); ++i) { gcry_sexp_t names, protos, privs; char *name, *proto; gcry_sexp_t accounts; OtrlPrivKey *p; //printf("reading account #:%d\n",i); /* Get the ith "account" S-exp */ accounts = gcry_sexp_nth(allkeys, i); /* It's really an "account" S-exp? */ token = gcry_sexp_nth_data(accounts, 0, &tokenlen); if (tokenlen != 7 || strncmp(token, "account", 7)) { gcry_sexp_release(accounts); gcry_sexp_release(allkeys); return gcry_error(GPG_ERR_UNUSABLE_SECKEY); } /* Extract the name, protocol, and privkey S-exps */ names = gcry_sexp_find_token(accounts, "name", 0); protos = gcry_sexp_find_token(accounts, "protocol", 0); privs = gcry_sexp_find_token(accounts, "private-key", 0); gcry_sexp_release(accounts); if (!names || !protos || !privs) { gcry_sexp_release(names); gcry_sexp_release(protos); gcry_sexp_release(privs); gcry_sexp_release(allkeys); return gcry_error(GPG_ERR_UNUSABLE_SECKEY); } /* Extract the actual name and protocol */ token = gcry_sexp_nth_data(names, 1, &tokenlen); if (!token) { gcry_sexp_release(names); gcry_sexp_release(protos); gcry_sexp_release(privs); gcry_sexp_release(allkeys); return gcry_error(GPG_ERR_UNUSABLE_SECKEY); } name = malloc(tokenlen + 1); if (!name) { gcry_sexp_release(names); gcry_sexp_release(protos); gcry_sexp_release(privs); gcry_sexp_release(allkeys); return gcry_error(GPG_ERR_ENOMEM); } memmove(name, token, tokenlen); name[tokenlen] = '\0'; gcry_sexp_release(names); token = gcry_sexp_nth_data(protos, 1, &tokenlen); if (!token) { free(name); gcry_sexp_release(protos); gcry_sexp_release(privs); gcry_sexp_release(allkeys); return gcry_error(GPG_ERR_UNUSABLE_SECKEY); } proto = malloc(tokenlen + 1); if (!proto) { free(name); gcry_sexp_release(protos); gcry_sexp_release(privs); gcry_sexp_release(allkeys); return gcry_error(GPG_ERR_ENOMEM); } memmove(proto, token, tokenlen); proto[tokenlen] = '\0'; gcry_sexp_release(protos); /* Make a new OtrlPrivKey entry */ p = malloc(sizeof(*p)); if (!p) { free(name); free(proto); gcry_sexp_release(privs); gcry_sexp_release(allkeys); return gcry_error(GPG_ERR_ENOMEM); } /* Fill it in and link it up */ p->accountname = name; p->protocol = proto; p->pubkey_type = OTRL_PUBKEY_TYPE_DSA; p->privkey = privs; p->next = us->privkey_root; if (p->next) { p->next->tous = &(p->next); } p->tous = &(us->privkey_root); us->privkey_root = p; err = jsapi_make_pubkey(&(p->pubkey_data), &(p->pubkey_datalen), p->privkey); if (err) { gcry_sexp_release(allkeys); otrl_privkey_forget(p); return gcry_error(GPG_ERR_UNUSABLE_SECKEY); } } gcry_sexp_release(allkeys); /* application should write out userstate to disk */ return gcry_error(GPG_ERR_NO_ERROR); }