/** * Converts a binary request to base64 with 64 characters per line * newline and '+' characters are escaped by %0A and %2B, respectively */ static char* escape_http_request(chunk_t req) { char *escaped_req = NULL; char *p1, *p2; int lines = 0; int plus = 0; int n = 0; /* compute and allocate the size of the base64-encoded request */ int len = 1 + 4 * ((req.len + 2) / 3); char *encoded_req = malloc(len); /* do the base64 conversion */ chunk_t base64 = chunk_to_base64(req, encoded_req); len = base64.len + 1; /* compute newline characters to be inserted every 64 characters */ lines = (len - 2) / 64; /* count number of + characters to be escaped */ p1 = encoded_req; while (*p1 != '\0') { if (*p1++ == '+') { plus++; } } escaped_req = malloc(len + 3 * (lines + plus)); /* escape special characters in the request */ p1 = encoded_req; p2 = escaped_req; while (*p1 != '\0') { if (n == 64) { memcpy(p2, "%0A", 3); p2 += 3; n = 0; } if (*p1 == '+') { memcpy(p2, "%2B", 3); p2 += 3; } else { *p2++ = *p1; } p1++; n++; } *p2 = '\0'; free(encoded_req); return escaped_req; }
END_TEST /******************************************************************************* * BASE64 encoding test */ START_TEST(test_base64) { /* test vectors from RFC 4648: * * BASE64("") = "" * BASE64("f") = "Zg==" * BASE64("fo") = "Zm8=" * BASE64("foo") = "Zm9v" * BASE64("foob") = "Zm9vYg==" * BASE64("fooba") = "Zm9vYmE=" * BASE64("foobar") = "Zm9vYmFy" */ typedef struct { char *in; char *out; } testdata_t; testdata_t test[] = { {"", ""}, {"f", "Zg=="}, {"fo", "Zm8="}, {"foo", "Zm9v"}, {"foob", "Zm9vYg=="}, {"fooba", "Zm9vYmE="}, {"foobar", "Zm9vYmFy"}, }; int i; for (i = 0; i < countof(test); i++) { chunk_t out; out = chunk_to_base64(chunk_create(test[i].in, strlen(test[i].in)), NULL); ck_assert_str_eq(out.ptr, test[i].out); free(out.ptr); } for (i = 0; i < countof(test); i++) { chunk_t out; out = chunk_from_base64(chunk_create(test[i].out, strlen(test[i].out)), NULL); fail_unless(strneq(out.ptr, test[i].in, out.len), "base64 conversion error - should '%s', is %#B", test[i].in, &out); free(out.ptr); } }
/** * 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; }
/** * Extract subject DN */ static int dn() { identification_t *id; certificate_t *cert; chunk_t chunk; enum { FORMAT_CONFIG, FORMAT_HEX, FORMAT_BASE64, FORMAT_BINARY, } format = FORMAT_CONFIG; char *arg, *file = NULL, *fmt; while (TRUE) { switch (command_getopt(&arg)) { case 'h': return command_usage(NULL); case 'f': if (streq(arg, "hex")) { format = FORMAT_HEX; } else if (streq(arg, "base64")) { format = FORMAT_BASE64; } else if (streq(arg, "bin")) { format = FORMAT_BINARY; } else if (!streq(arg, "config")) { return command_usage( "invalid output format"); } continue; case 'i': file = arg; continue; case EOF: break; default: return command_usage("invalid --print option"); } break; } if (file) { cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509, BUILD_FROM_FILE, file, BUILD_END); } else { chunk_t chunk; set_file_mode(stdin, CERT_ASN1_DER); if (!chunk_from_fd(0, &chunk)) { fprintf(stderr, "reading input failed: %s\n", strerror(errno)); return 1; } cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509, BUILD_BLOB, chunk, BUILD_END); free(chunk.ptr); } if (!cert) { fprintf(stderr, "parsing input failed\n"); return 1; } id = cert->get_subject(cert); if (!id) { fprintf(stderr, "failed to get certificate's subject DN\n"); cert->destroy(cert); return 1; } fmt = "%.*s\n"; switch (format) { case FORMAT_CONFIG: fmt = "\"asn1dn:#%.*s\"\n"; /* fall-through */ case FORMAT_HEX: chunk = chunk_to_hex(id->get_encoding(id), NULL, FALSE); printf(fmt, (int)chunk.len, chunk.ptr); chunk_free(&chunk); break; case FORMAT_BASE64: chunk = chunk_to_base64(id->get_encoding(id), NULL); printf(fmt, (int)chunk.len, chunk.ptr); chunk_free(&chunk); break; case FORMAT_BINARY: chunk = id->get_encoding(id); if (fwrite(chunk.ptr, chunk.len, 1, stdout) != 1) { fprintf(stderr, "writing subject DN failed\n"); } break; } cert->destroy(cert); return 0; }
/** * 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; }