/** * Build a PGPv3 fingerprint */ static bool build_v3_fingerprint(chunk_t *encoding, va_list args) { hasher_t *hasher; chunk_t n, e; if (cred_encoding_args(args, CRED_PART_RSA_MODULUS, &n, CRED_PART_RSA_PUB_EXP, &e, CRED_PART_END)) { hasher = lib->crypto->create_hasher(lib->crypto, HASH_MD5); if (!hasher) { DBG1(DBG_LIB, "MD5 hash algorithm not supported, PGP" " fingerprinting failed"); return FALSE; } /* remove leading zero bytes before hashing modulus and exponent */ while (n.len > 0 && n.ptr[0] == 0x00) { n = chunk_skip(n, 1); } while (e.len > 0 && e.ptr[0] == 0x00) { e = chunk_skip(e, 1); } hasher->allocate_hash(hasher, n, NULL); hasher->allocate_hash(hasher, e, encoding); hasher->destroy(hasher); return TRUE; } return FALSE; }
/** * Encode an RSA public key in DNSKEY format (RFC 3110) */ static bool build_pub(chunk_t *encoding, va_list args) { chunk_t n, e, pubkey; size_t exp_len; u_char *pos; if (cred_encoding_args(args, CRED_PART_RSA_MODULUS, &n, CRED_PART_RSA_PUB_EXP, &e, CRED_PART_END)) { /* remove leading zeros in exponent and modulus */ while (*e.ptr == 0) { e = chunk_skip(e, 1); } while (*n.ptr == 0) { n = chunk_skip(n, 1); } if (e.len < 256) { /* exponent length fits into a single octet */ exp_len = 1; pubkey = chunk_alloc(exp_len + e.len + n.len); pubkey.ptr[0] = (char)e.len; } else if (e.len < 65536) { /* exponent length fits into two octets preceded by zero octet */ exp_len = 3; pubkey = chunk_alloc(exp_len + e.len + n.len); pubkey.ptr[0] = 0x00; htoun16(pubkey.ptr + 1, e.len); } else { /* exponent length is too large */ return FALSE; } /* copy exponent and modulus and convert to base64 format */ pos = pubkey.ptr + exp_len; memcpy(pos, e.ptr, e.len); pos += e.len; memcpy(pos, n.ptr, n.len); *encoding = chunk_to_base64(pubkey, NULL); chunk_free(&pubkey); return TRUE; } return FALSE; }
/** * See header. */ bool pem_encoder_encode(cred_encoding_type_t type, chunk_t *encoding, va_list args) { chunk_t asn1; char *label; u_char *pos; size_t len, written, pem_chars, pem_lines; chunk_t n, e, d, p, q, exp1, exp2, coeff, to_free = chunk_empty; switch (type) { case PUBKEY_PEM: label ="PUBLIC KEY"; /* direct PKCS#1 PEM encoding */ if (cred_encoding_args(args, CRED_PART_RSA_PUB_ASN1_DER, &asn1, CRED_PART_END) || cred_encoding_args(args, CRED_PART_ECDSA_PUB_ASN1_DER, &asn1, CRED_PART_END) || cred_encoding_args(args, CRED_PART_EDDSA_PUB_ASN1_DER, &asn1, CRED_PART_END) || cred_encoding_args(args, CRED_PART_BLISS_PUB_ASN1_DER, &asn1, CRED_PART_END)) { break; } /* indirect PEM encoding from components */ if (cred_encoding_args(args, CRED_PART_RSA_MODULUS, &n, CRED_PART_RSA_PUB_EXP, &e, CRED_PART_END)) { if (lib->encoding->encode(lib->encoding, PUBKEY_SPKI_ASN1_DER, NULL, &asn1, CRED_PART_RSA_MODULUS, n, CRED_PART_RSA_PUB_EXP, e, CRED_PART_END)) { to_free = asn1; break; } } return FALSE; case PRIVKEY_PEM: label ="RSA PRIVATE KEY"; /* direct PKCS#1 PEM encoding */ if (cred_encoding_args(args, CRED_PART_RSA_PRIV_ASN1_DER, &asn1, CRED_PART_END)) { break; } /* indirect PEM encoding from components */ if (cred_encoding_args(args, CRED_PART_RSA_MODULUS, &n, CRED_PART_RSA_PUB_EXP, &e, CRED_PART_RSA_PRIV_EXP, &d, CRED_PART_RSA_PRIME1, &p, CRED_PART_RSA_PRIME2, &q, CRED_PART_RSA_EXP1, &exp1, CRED_PART_RSA_EXP2, &exp2, CRED_PART_RSA_COEFF, &coeff, CRED_PART_END)) { if (lib->encoding->encode(lib->encoding, PRIVKEY_ASN1_DER, NULL, &asn1, CRED_PART_RSA_MODULUS, n, CRED_PART_RSA_PUB_EXP, e, CRED_PART_RSA_PRIV_EXP, d, CRED_PART_RSA_PRIME1, p, CRED_PART_RSA_PRIME2, q, CRED_PART_RSA_EXP1, exp1, CRED_PART_RSA_EXP2, exp2, CRED_PART_RSA_COEFF, coeff, CRED_PART_END)) { to_free = asn1; break; } } if (cred_encoding_args(args, CRED_PART_ECDSA_PRIV_ASN1_DER, &asn1, CRED_PART_END)) { label ="EC PRIVATE KEY"; break; } if (cred_encoding_args(args, CRED_PART_BLISS_PRIV_ASN1_DER, &asn1, CRED_PART_END)) { label ="BLISS PRIVATE KEY"; break; } if (cred_encoding_args(args, CRED_PART_EDDSA_PRIV_ASN1_DER, &asn1, CRED_PART_END)) { label ="PRIVATE KEY"; break; } return FALSE; case CERT_PEM: if (cred_encoding_args(args, CRED_PART_X509_ASN1_DER, &asn1, CRED_PART_END)) { /* PEM encode x509 certificate */ label = "CERTIFICATE"; break; } if (cred_encoding_args(args, CRED_PART_X509_CRL_ASN1_DER, &asn1, CRED_PART_END)) { /* PEM encode CRL */ label = "X509 CRL"; break; } if (cred_encoding_args(args, CRED_PART_PKCS10_ASN1_DER, &asn1, CRED_PART_END)) { /* PEM encode PKCS10 certificate reqeuest */ label = "CERTIFICATE REQUEST"; break; } if (cred_encoding_args(args, CRED_PART_X509_AC_ASN1_DER, &asn1, CRED_PART_END)) { label = "ATTRIBUTE CERTIFICATE"; break; } default: return FALSE; } /* compute and allocate maximum size of PEM object */ pem_chars = 4 * ((asn1.len + 2) / 3); pem_lines = (asn1.len + BYTES_PER_LINE - 1) / BYTES_PER_LINE; *encoding = chunk_alloc(5 + 2*(6 + strlen(label) + 6) + 3 + pem_chars + pem_lines); pos = encoding->ptr; len = encoding->len; /* write PEM header */ written = snprintf(pos, len, "-----BEGIN %s-----\n", label); pos += written; len -= written; /* write PEM body */ while (pem_lines--) { chunk_t asn1_line, pem_line; asn1_line = chunk_create(asn1.ptr, min(asn1.len, BYTES_PER_LINE)); asn1.ptr += asn1_line.len; asn1.len -= asn1_line.len; pem_line = chunk_to_base64(asn1_line, pos); pos += pem_line.len; len -= pem_line.len; *pos = '\n'; pos++; len--; } chunk_clear(&to_free); /* write PEM trailer */ written = snprintf(pos, len, "-----END %s-----", label); pos += written; len -= written; /* replace termination null character with newline */ *pos = '\n'; pos++; len--; /* compute effective length of PEM object */ encoding->len = pos - encoding->ptr; return TRUE; }
/** * Encode the public key as Base64 encoded SSH key blob */ static bool build_public_key(chunk_t *encoding, va_list args) { bio_writer_t *writer; chunk_t n, e; if (cred_encoding_args(args, CRED_PART_RSA_MODULUS, &n, CRED_PART_RSA_PUB_EXP, &e, CRED_PART_END)) { writer = bio_writer_create(0); writer->write_data32(writer, chunk_from_str("ssh-rsa")); writer->write_data32(writer, e); writer->write_data32(writer, n); *encoding = chunk_to_base64(writer->get_buf(writer), NULL); writer->destroy(writer); return TRUE; } else if (cred_encoding_args(args, CRED_PART_EDDSA_PUB_ASN1_DER, &n, CRED_PART_END)) { chunk_t alg; char *prefix; int oid; /* parse subjectPublicKeyInfo */ if (asn1_unwrap(&n, &n) != ASN1_SEQUENCE) { return FALSE; } oid = asn1_parse_algorithmIdentifier(n, 1, NULL); switch (oid) { case OID_ED25519: prefix = "ssh-ed25519"; break; case OID_ED448: prefix = "ssh-ed448"; break; default: return FALSE; } if (asn1_unwrap(&n, &alg) != ASN1_SEQUENCE || asn1_unwrap(&n, &n) != ASN1_BIT_STRING || !n.len) { return FALSE; } writer = bio_writer_create(0); writer->write_data32(writer, chunk_from_str(prefix)); writer->write_data32(writer, chunk_skip(n, 1)); *encoding = chunk_to_base64(writer->get_buf(writer), NULL); writer->destroy(writer); return TRUE; } else if (cred_encoding_args(args, CRED_PART_ECDSA_PUB_ASN1_DER, &n, CRED_PART_END)) { chunk_t params, alg, q; int oid; /* parse subjectPublicKeyInfo */ if (asn1_unwrap(&n, &n) != ASN1_SEQUENCE) { return FALSE; } oid = asn1_parse_algorithmIdentifier(n, 1, ¶ms); if (oid != OID_EC_PUBLICKEY || asn1_unwrap(¶ms, ¶ms) != ASN1_OID) { return FALSE; } oid = asn1_known_oid(params); if (oid == OID_UNKNOWN) { return FALSE; } if (asn1_unwrap(&n, &alg) != ASN1_SEQUENCE || asn1_unwrap(&n, &q) != ASN1_BIT_STRING) { return FALSE; } writer = bio_writer_create(0); write_ec_identifier(writer, ECDSA_PREFIX, oid, params); write_ec_identifier(writer, "", oid, params); q = chunk_skip_zero(q); writer->write_data32(writer, q); *encoding = chunk_to_base64(writer->get_buf(writer), NULL); writer->destroy(writer); return TRUE; } return FALSE; }