/* add a key to a secret keyring */ int __ops_add_to_secring(__ops_keyring_t *keyring, const __ops_seckey_t *seckey) { const __ops_pubkey_t *pubkey; __ops_key_t *key; if (__ops_get_debug_level(__FILE__)) { fprintf(stderr, "__ops_add_to_secring\n"); } if (keyring->keyc > 0) { key = &keyring->keys[keyring->keyc - 1]; if (__ops_get_debug_level(__FILE__) && key->key.pubkey.alg == OPS_PKA_DSA && seckey->pubkey.alg == OPS_PKA_ELGAMAL) { fprintf(stderr, "__ops_add_to_secring: found elgamal seckey\n"); } } EXPAND_ARRAY(keyring, key); key = &keyring->keys[keyring->keyc++]; (void) memset(key, 0x0, sizeof(*key)); pubkey = &seckey->pubkey; __ops_keyid(key->sigid, OPS_KEY_ID_SIZE, pubkey, keyring->hashtype); __ops_fingerprint(&key->sigfingerprint, pubkey, keyring->hashtype); key->type = OPS_PTAG_CT_SECRET_KEY; key->key.seckey = *seckey; if (__ops_get_debug_level(__FILE__)) { fprintf(stderr, "__ops_add_to_secring: keyc %u\n", keyring->keyc); } return 1; }
/* return the next key which matches, starting searching at *from */ static const __ops_key_t * getkeybyname(__ops_io_t *io, const __ops_keyring_t *keyring, const char *name, unsigned *from) { const __ops_key_t *kp; uint8_t **uidp; unsigned i = 0; __ops_key_t *keyp; unsigned savedstart; regex_t r; uint8_t keyid[OPS_KEY_ID_SIZE + 1]; size_t len; if (!keyring || !name || !from) { return NULL; } len = strlen(name); if (__ops_get_debug_level(__FILE__)) { (void) fprintf(io->outs, "[%u] name '%s', len %zu\n", *from, name, len); } /* first try name as a keyid */ (void) memset(keyid, 0x0, sizeof(keyid)); str2keyid(name, keyid, sizeof(keyid)); if (__ops_get_debug_level(__FILE__)) { hexdump(io->outs, "keyid", keyid, 4); } savedstart = *from; if ((kp = __ops_getkeybyid(io, keyring, keyid, from, NULL)) != NULL) { return kp; } *from = savedstart; if (__ops_get_debug_level(__FILE__)) { (void) fprintf(io->outs, "regex match '%s' from %u\n", name, *from); } /* match on full name or email address as a NOSUB, ICASE regexp */ (void) regcomp(&r, name, REG_EXTENDED | REG_ICASE); for (keyp = &keyring->keys[*from]; *from < keyring->keyc; *from += 1, keyp++) { uidp = keyp->uids; for (i = 0 ; i < keyp->uidc; i++, uidp++) { if (regexec(&r, (char *)*uidp, 0, NULL, 0) == 0) { if (__ops_get_debug_level(__FILE__)) { (void) fprintf(io->outs, "MATCHED keyid \"%s\" len %" PRIsize "u\n", (char *) *uidp, len); } regfree(&r); return keyp; } } } regfree(&r); return NULL; }
/** \ingroup HighLevel_KeyringFind \brief Finds key in keyring from its Key ID \param keyring Keyring to be searched \param keyid ID of required key \return Pointer to key, if found; NULL, if not found \note This returns a pointer to the key inside the given keyring, not a copy. Do not free it after use. */ const __ops_key_t * __ops_getkeybyid(__ops_io_t *io, const __ops_keyring_t *keyring, const uint8_t *keyid, unsigned *from, __ops_pubkey_t **pubkey) { uint8_t nullid[OPS_KEY_ID_SIZE]; (void) memset(nullid, 0x0, sizeof(nullid)); for ( ; keyring && *from < keyring->keyc; *from += 1) { if (__ops_get_debug_level(__FILE__)) { hexdump(io->errs, "keyring keyid", keyring->keys[*from].sigid, OPS_KEY_ID_SIZE); hexdump(io->errs, "keyid", keyid, OPS_KEY_ID_SIZE); } if (memcmp(keyring->keys[*from].sigid, keyid, OPS_KEY_ID_SIZE) == 0 || memcmp(&keyring->keys[*from].sigid[OPS_KEY_ID_SIZE / 2], keyid, OPS_KEY_ID_SIZE / 2) == 0) { if (pubkey) { *pubkey = &keyring->keys[*from].key.pubkey; } return &keyring->keys[*from]; } if (memcmp(&keyring->keys[*from].encid, nullid, sizeof(nullid)) == 0) { continue; } if (memcmp(&keyring->keys[*from].encid, keyid, OPS_KEY_ID_SIZE) == 0 || memcmp(&keyring->keys[*from].encid[OPS_KEY_ID_SIZE / 2], keyid, OPS_KEY_ID_SIZE / 2) == 0) { if (pubkey) { *pubkey = &keyring->keys[*from].enckey; } return &keyring->keys[*from]; } } return NULL; }
/* add a key to a public keyring */ int __ops_add_to_pubring(__ops_keyring_t *keyring, const __ops_pubkey_t *pubkey, __ops_content_enum tag) { __ops_key_t *key; time_t duration; if (__ops_get_debug_level(__FILE__)) { fprintf(stderr, "__ops_add_to_pubring (type %u)\n", tag); } switch(tag) { case OPS_PTAG_CT_PUBLIC_KEY: EXPAND_ARRAY(keyring, key); key = &keyring->keys[keyring->keyc++]; duration = key->key.pubkey.duration; (void) memset(key, 0x0, sizeof(*key)); key->type = tag; __ops_keyid(key->sigid, OPS_KEY_ID_SIZE, pubkey, keyring->hashtype); __ops_fingerprint(&key->sigfingerprint, pubkey, keyring->hashtype); key->key.pubkey = *pubkey; key->key.pubkey.duration = duration; return 1; case OPS_PTAG_CT_PUBLIC_SUBKEY: /* subkey is not the first */ key = &keyring->keys[keyring->keyc - 1]; __ops_keyid(key->encid, OPS_KEY_ID_SIZE, pubkey, keyring->hashtype); duration = key->key.pubkey.duration; (void) memcpy(&key->enckey, pubkey, sizeof(key->enckey)); key->enckey.duration = duration; return 1; default: return 0; } }
static void sha224_add(__ops_hash_t *hash, const uint8_t *data, unsigned length) { if (__ops_get_debug_level(__FILE__)) { hexdump(stderr, "sha224_add", data, length); } SHA224_Update(hash->data, data, length); }
unsigned __ops_dsa_verify(const uint8_t *hash, size_t hash_length, const __ops_dsa_sig_t *sig, const __ops_dsa_pubkey_t *dsa) { unsigned qlen; DSA_SIG *osig; DSA *odsa; int ret; osig = DSA_SIG_new(); osig->r = sig->r; osig->s = sig->s; odsa = DSA_new(); odsa->p = dsa->p; odsa->q = dsa->q; odsa->g = dsa->g; odsa->pub_key = dsa->y; if (__ops_get_debug_level(__FILE__)) { hexdump(stderr, "input hash", hash, hash_length); (void) fprintf(stderr, "Q=%d\n", BN_num_bytes(odsa->q)); } if ((qlen = (unsigned)BN_num_bytes(odsa->q)) < hash_length) { hash_length = qlen; } ret = DSA_do_verify(hash, (int)hash_length, osig, odsa); if (__ops_get_debug_level(__FILE__)) { (void) fprintf(stderr, "ret=%d\n", ret); } if (ret < 0) { (void) fprintf(stderr, "__ops_dsa_verify: DSA verification\n"); return 0; } odsa->p = odsa->q = odsa->g = odsa->pub_key = NULL; DSA_free(odsa); osig->r = osig->s = NULL; DSA_SIG_free(osig); return (unsigned)ret; }
static unsigned sha224_finish(__ops_hash_t *hash, uint8_t *out) { SHA224_Final(out, hash->data); if (__ops_get_debug_level(__FILE__)) { hexdump(stderr, "sha224_finish", out, SHA224_DIGEST_LENGTH); } free(hash->data); hash->data = NULL; return SHA224_DIGEST_LENGTH; }
static unsigned sha1_finish(__ops_hash_t *hash, uint8_t *out) { SHA1_Final(out, hash->data); if (__ops_get_debug_level(__FILE__)) { hexdump(stderr, "sha1_finish", out, OPS_SHA1_HASH_SIZE); } free(hash->data); hash->data = NULL; return OPS_SHA1_HASH_SIZE; }
int __ops_keyring_json(__ops_io_t *io, const __ops_keyring_t *keyring, mj_t *obj, const int psigs) { __ops_key_t *key; unsigned n; (void) memset(obj, 0x0, sizeof(*obj)); mj_create(obj, "array"); obj->size = keyring->keyvsize; if (__ops_get_debug_level(__FILE__)) { (void) fprintf(io->errs, "__ops_keyring_json: vsize %u\n", obj->size); } if ((obj->value.v = calloc(sizeof(*obj->value.v), obj->size)) == NULL) { (void) fprintf(io->errs, "calloc failure\n"); return 0; } for (n = 0, key = keyring->keys; n < keyring->keyc; ++n, ++key) { if (__ops_is_key_secret(key)) { __ops_sprint_mj(io, keyring, key, &obj->value.v[obj->c], "sec", &key->key.seckey.pubkey, psigs); } else { __ops_sprint_mj(io, keyring, key, &obj->value.v[obj->c], "signature ", &key->key.pubkey, psigs); } if (obj->value.v[obj->c].type != 0) { obj->c += 1; } } if (__ops_get_debug_level(__FILE__)) { char *s; mj_asprint(&s, obj); (void) fprintf(stderr, "__ops_keyring_json: '%s'\n", s); free(s); } return 1; }
/** \ingroup Core_Crypto \brief Decrypts RSA-encrypted data \param out Where to write the plaintext \param in Encrypted data \param length Length of encrypted data \param seckey RSA secret key \param pubkey RSA public key \return size of recovered plaintext */ int __ops_rsa_private_decrypt(uint8_t *out, const uint8_t *in, size_t length, const __ops_rsa_seckey_t *seckey, const __ops_rsa_pubkey_t *pubkey) { RSA *keypair; int n; char errbuf[1024]; keypair = RSA_new(); keypair->n = pubkey->n; /* XXX: do we need n? */ keypair->d = seckey->d; keypair->p = seckey->q; keypair->q = seckey->p; /* debug */ keypair->e = pubkey->e; if (RSA_check_key(keypair) != 1) { (void) fprintf(stderr, "RSA_check_key is not set\n"); return 0; } /* end debug */ n = RSA_private_decrypt((int)length, in, out, keypair, RSA_NO_PADDING); if (__ops_get_debug_level(__FILE__)) { printf("__ops_rsa_private_decrypt: n=%d\n",n); } errbuf[0] = '\0'; if (n == -1) { unsigned long err = ERR_get_error(); ERR_error_string(err, &errbuf[0]); (void) fprintf(stderr, "openssl error : %s\n", errbuf); } keypair->n = keypair->d = keypair->p = keypair->q = NULL; RSA_free(keypair); return n; }
/** \ingroup HighLevel_KeyGenerate \brief Generates an RSA keypair \param numbits Modulus size \param e Public Exponent \param keydata Pointer to keydata struct to hold new key \return 1 if key generated successfully; otherwise 0 \note It is the caller's responsibility to call __ops_keydata_free(keydata) */ static unsigned rsa_generate_keypair(__ops_key_t *keydata, const int numbits, const unsigned long e, const char *hashalg, const char *cipher) { __ops_seckey_t *seckey; RSA *rsa; BN_CTX *ctx; __ops_output_t *output; __ops_memory_t *mem; ctx = BN_CTX_new(); __ops_keydata_init(keydata, OPS_PTAG_CT_SECRET_KEY); seckey = __ops_get_writable_seckey(keydata); /* generate the key pair */ rsa = RSA_generate_key(numbits, e, NULL, NULL); /* populate __ops key from ssl key */ seckey->pubkey.version = OPS_V4; seckey->pubkey.birthtime = time(NULL); seckey->pubkey.days_valid = 0; seckey->pubkey.alg = OPS_PKA_RSA; seckey->pubkey.key.rsa.n = BN_dup(rsa->n); seckey->pubkey.key.rsa.e = BN_dup(rsa->e); seckey->s2k_usage = OPS_S2KU_ENCRYPTED_AND_HASHED; seckey->s2k_specifier = OPS_S2KS_SALTED; /* seckey->s2k_specifier=OPS_S2KS_SIMPLE; */ if ((seckey->hash_alg = __ops_str_to_hash_alg(hashalg)) == OPS_HASH_UNKNOWN) { seckey->hash_alg = OPS_HASH_SHA1; } seckey->alg = __ops_str_to_cipher(cipher); seckey->octetc = 0; seckey->checksum = 0; seckey->key.rsa.d = BN_dup(rsa->d); seckey->key.rsa.p = BN_dup(rsa->p); seckey->key.rsa.q = BN_dup(rsa->q); seckey->key.rsa.u = BN_mod_inverse(NULL, rsa->p, rsa->q, ctx); if (seckey->key.rsa.u == NULL) { (void) fprintf(stderr, "seckey->key.rsa.u is NULL\n"); return 0; } BN_CTX_free(ctx); RSA_free(rsa); __ops_keyid(keydata->sigid, OPS_KEY_ID_SIZE, &keydata->key.seckey.pubkey, seckey->hash_alg); __ops_fingerprint(&keydata->sigfingerprint, &keydata->key.seckey.pubkey, seckey->hash_alg); /* Generate checksum */ output = NULL; mem = NULL; __ops_setup_memory_write(&output, &mem, 128); __ops_push_checksum_writer(output, seckey); switch (seckey->pubkey.alg) { case OPS_PKA_DSA: return __ops_write_mpi(output, seckey->key.dsa.x); case OPS_PKA_RSA: case OPS_PKA_RSA_ENCRYPT_ONLY: case OPS_PKA_RSA_SIGN_ONLY: if (!__ops_write_mpi(output, seckey->key.rsa.d) || !__ops_write_mpi(output, seckey->key.rsa.p) || !__ops_write_mpi(output, seckey->key.rsa.q) || !__ops_write_mpi(output, seckey->key.rsa.u)) { return 0; } break; case OPS_PKA_ELGAMAL: return __ops_write_mpi(output, seckey->key.elgamal.x); default: (void) fprintf(stderr, "Bad seckey->pubkey.alg\n"); return 0; } /* close rather than pop, since its the only one on the stack */ __ops_writer_close(output); __ops_teardown_memory_write(output, mem); /* should now have checksum in seckey struct */ /* test */ if (__ops_get_debug_level(__FILE__)) { test_seckey(seckey); } return 1; }
/* format a JSON object */ static void format_json_key(FILE *fp, mj_t *obj, const int psigs) { int64_t birthtime; int64_t duration; time_t now; char tbuf[32]; char *s; mj_t *sub; int i; if (__ops_get_debug_level(__FILE__)) { mj_asprint(&s, obj); (void) fprintf(stderr, "formatobj: json is '%s'\n", s); free(s); } if (obj->c == 2 && obj->value.v[1].type == MJ_STRING && strcmp(obj->value.v[1].value.s, "[REVOKED]") == 0) { /* whole key has been rovoked - just return */ return; } pobj(fp, &obj->value.v[mj_object_find(obj, "header", 0, 2) + 1], 0); p(fp, " ", NULL); pobj(fp, &obj->value.v[mj_object_find(obj, "key bits", 0, 2) + 1], 0); p(fp, "/", NULL); pobj(fp, &obj->value.v[mj_object_find(obj, "pka", 0, 2) + 1], 0); p(fp, " ", NULL); pobj(fp, &obj->value.v[mj_object_find(obj, "key id", 0, 2) + 1], 0); birthtime = strtoll(obj->value.v[mj_object_find(obj, "birthtime", 0, 2) + 1].value.s, NULL, 10); p(fp, " ", ptimestr(tbuf, sizeof(tbuf), birthtime), NULL); duration = strtoll(obj->value.v[mj_object_find(obj, "duration", 0, 2) + 1].value.s, NULL, 10); if (duration > 0) { now = time(NULL); p(fp, " ", (birthtime + duration < now) ? "[EXPIRED " : "[EXPIRES ", ptimestr(tbuf, sizeof(tbuf), birthtime + duration), "]", NULL); } p(fp, "\n", "Key fingerprint: ", NULL); pobj(fp, &obj->value.v[mj_object_find(obj, "fingerprint", 0, 2) + 1], 0); p(fp, "\n", NULL); /* go to field after \"duration\" */ for (i = mj_object_find(obj, "duration", 0, 2) + 2; i < mj_arraycount(obj) ; i += 2) { if (strcmp(obj->value.v[i].value.s, "uid") == 0) { sub = &obj->value.v[i + 1]; p(fp, "uid", NULL); pobj(fp, &sub->value.v[0], (psigs) ? 4 : 14); /* human name */ pobj(fp, &sub->value.v[1], 1); /* any revocation */ p(fp, "\n", NULL); } else if (strcmp(obj->value.v[i].value.s, "encryption") == 0) { sub = &obj->value.v[i + 1]; p(fp, "encryption", NULL); pobj(fp, &sub->value.v[0], 1); /* size */ p(fp, "/", NULL); pobj(fp, &sub->value.v[1], 0); /* alg */ p(fp, " ", NULL); pobj(fp, &sub->value.v[2], 0); /* id */ p(fp, " ", ptimestr(tbuf, sizeof(tbuf), strtoll(sub->value.v[3].value.s, NULL, 10)), "\n", NULL); } else if (strcmp(obj->value.v[i].value.s, "sig") == 0) { sub = &obj->value.v[i + 1]; p(fp, "sig", NULL); pobj(fp, &sub->value.v[0], 8); /* size */ p(fp, " ", ptimestr(tbuf, sizeof(tbuf), strtoll(sub->value.v[1].value.s, NULL, 10)), " ", NULL); /* time */ pobj(fp, &sub->value.v[2], 0); /* human name */ p(fp, "\n", NULL); } else { fprintf(stderr, "weird '%s'\n", obj->value.v[i].value.s); pobj(fp, &obj->value.v[i], 0); /* human name */ } } p(fp, "\n", NULL); }