+ const unsigned char *p = blob, *end = blob + blen;
+
+ rsa = RSA_new();
+ if (!rsa)
+ return -E_BIGNUM;
+ ret = read_bignum(p, end - p, &rsa->e);
+ if (ret < 0)
+ goto fail;
+ p += ret;
+ ret = read_bignum(p, end - p, &rsa->n);
+ if (ret < 0)
+ goto fail;
+ *result = rsa;
+ return 1;
+fail:
+ RSA_free(rsa);
+ return ret;
+}
+
+int get_asymmetric_key(const char *key_file, int private,
+ struct asymmetric_key **result)
+{
+ struct asymmetric_key *key = NULL;
+ void *map = NULL;
+ unsigned char *blob = NULL;
+ size_t map_size, blob_size, decoded_size;
+ int ret, ret2;
+ char *cp;
+
+ key = para_malloc(sizeof(*key));
+ if (private) {
+ ret = get_openssl_key(key_file, &key->rsa, LOAD_PRIVATE_KEY);
+ goto out;
+ }
+ ret = mmap_full_file(key_file, O_RDONLY, &map, &map_size, NULL);
+ if (ret < 0)
+ goto out;
+ ret = is_ssh_rsa_key(map, map_size);
+ if (!ret) {
+ ret = para_munmap(map, map_size);
+ map = NULL;
+ if (ret < 0)
+ goto out;
+ ret = get_openssl_key(key_file, &key->rsa, LOAD_PUBLIC_KEY);
+ goto out;
+ }
+ cp = map + ret;
+ PARA_INFO_LOG("decoding public rsa-ssh key %s\n", key_file);
+ ret = -ERRNO_TO_PARA_ERROR(EOVERFLOW);
+ if (map_size > INT_MAX / 4)
+ goto out_unmap;
+ blob_size = 2 * map_size;
+ blob = para_malloc(blob_size);
+ ret = uudecode(cp, blob, blob_size);
+ if (ret < 0)
+ goto out_unmap;
+ decoded_size = ret;
+ ret = check_ssh_key_header(blob, decoded_size);
+ if (ret < 0)
+ goto out_unmap;
+ ret = read_rsa_bignums(blob + ret, decoded_size - ret, &key->rsa);
+ if (ret < 0)
+ goto out_unmap;
+ ret = RSA_size(key->rsa);
+out_unmap:
+ ret2 = para_munmap(map, map_size);
+ if (ret >= 0 && ret2 < 0)
+ ret = ret2;
+out:
+ if (ret < 0) {
+ free(key);
+ *result = NULL;
+ PARA_ERROR_LOG("key %s: %s\n", key_file, para_strerror(-ret));
+ } else
+ *result = key;
+ free(blob);
+ return ret;
+}
+
+void free_asymmetric_key(struct asymmetric_key *key)
+{
+ if (!key)
+ return;
+ RSA_free(key->rsa);
+ free(key);
+}
+
+int priv_decrypt(const char *key_file, unsigned char *outbuf,
+ unsigned char *inbuf, int inlen)
+{
+ struct asymmetric_key *priv;
+ int ret;