/** * Load a RSA public key from DNSKEY RR data */ static dnskey_public_key_t *parse_rsa_public_key(chunk_t blob) { chunk_t n, e; if (blob.len < 3) { DBG1(DBG_LIB, "RFC 3110 public key blob too short for exponent length"); return NULL; } if (blob.ptr[0]) { e.len = blob.ptr[0]; blob = chunk_skip(blob, 1); } else { e.len = blob.ptr[1] * 256 + blob.ptr[2]; blob = chunk_skip(blob, 3); } e.ptr = blob.ptr; if (e.len >= blob.len) { DBG1(DBG_LIB, "RFC 3110 public key blob too short for exponent"); return NULL; } n = chunk_skip(blob, e.len); return lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_RSA, BUILD_RSA_MODULUS, n, BUILD_RSA_PUB_EXP, e, BUILD_END); }
/** * 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; }
/** * Load a generic public key from a DNSKEY RR blob */ static dnskey_public_key_t *parse_public_key(chunk_t blob) { dnskey_rr_t *rr = (dnskey_rr_t*)blob.ptr; if (blob.len < sizeof(dnskey_rr_t)) { DBG1(DBG_LIB, "DNSKEY too short"); return NULL; } blob = chunk_skip(blob, sizeof(dnskey_rr_t)); switch (rr->algorithm) { case DNSKEY_ALG_RSA_MD5: case DNSKEY_ALG_RSA_SHA1: case DNSKEY_ALG_RSA_SHA1_NSEC3_SHA1: case DNSKEY_ALG_RSA_SHA256: case DNSKEY_ALG_RSA_SHA512: return lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_RSA, BUILD_BLOB_DNSKEY, blob, BUILD_END); default: DBG1(DBG_LIB, "DNSKEY public key algorithm %d not supported", rr->algorithm); return NULL; } }
/** * find a boundary of the form -----tag name----- */ static bool find_boundary(char* tag, chunk_t *line) { chunk_t name = chunk_empty; if (!present("-----", line) || !present(tag, line) || *line->ptr != ' ') { return FALSE; } *line = chunk_skip(*line, 1); /* extract name */ name.ptr = line->ptr; while (line->len > 0) { if (present("-----", line)) { DBG2(DBG_ASN, " -----%s %.*s-----", tag, (int)name.len, name.ptr); return TRUE; } line->ptr++; line->len--; name.len++; } return FALSE; }
static int fmemwrite(chunk_t *cookie, const char *buf, int size) { int len; len = min(size, cookie->len); memcpy(cookie->ptr, buf, len); *cookie = chunk_skip(*cookie, len); return len; }
static int fmemread(chunk_t *cookie, char *buf, int size) { int len; len = min(size, cookie->len); memcpy(buf, cookie->ptr, len); *cookie = chunk_skip(*cookie, len); return len; }
/* * See header. */ int asn1_unwrap(chunk_t *blob, chunk_t *inner) { chunk_t res; u_char len; int type; if (blob->len < 2) { return ASN1_INVALID; } type = blob->ptr[0]; len = blob->ptr[1]; *blob = chunk_skip(*blob, 2); if ((len & 0x80) == 0) { /* single length octet */ res.len = len; } else { /* composite length, determine number of length octets */ len &= 0x7f; if (len == 0 || len > sizeof(res.len)) { return ASN1_INVALID; } res.len = 0; while (len-- > 0) { res.len = 256 * res.len + blob->ptr[0]; *blob = chunk_skip(*blob, 1); } } if (res.len > blob->len) { return ASN1_INVALID; } res.ptr = blob->ptr; *blob = chunk_skip(*blob, res.len); /* updating inner not before we are finished allows a caller to pass * blob = inner */ *inner = res; return type; }
/** * Load a generic public key from an ASN.1 encoded blob */ static public_key_t *parse_public_key(chunk_t blob) { asn1_parser_t *parser; chunk_t object; int objectID; public_key_t *key = NULL; key_type_t type = KEY_ANY; parser = asn1_parser_create(pkinfoObjects, blob); while (parser->iterate(parser, &objectID, &object)) { switch (objectID) { case PKINFO_SUBJECT_PUBLIC_KEY_ALGORITHM: { int oid = asn1_parse_algorithmIdentifier(object, parser->get_level(parser)+1, NULL); if (oid == OID_RSA_ENCRYPTION || oid == OID_RSAES_OAEP) { type = KEY_RSA; } else if (oid == OID_EC_PUBLICKEY) { /* we need the whole subjectPublicKeyInfo for EC public keys */ key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ECDSA, BUILD_BLOB_ASN1_DER, blob, BUILD_END); goto end; } else { /* key type not supported */ goto end; } break; } case PKINFO_SUBJECT_PUBLIC_KEY: if (object.len > 0 && *object.ptr == 0x00) { /* skip initial bit string octet defining 0 unused bits */ object = chunk_skip(object, 1); } DBG2(DBG_ASN, "-- > --"); key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, type, BUILD_BLOB_ASN1_DER, object, BUILD_END); DBG2(DBG_ASN, "-- < --"); break; } } end: parser->destroy(parser); return key; }
/* * Defined in header. */ size_t asn1_length(chunk_t *blob) { u_char n; size_t len; if (blob->len < 2) { DBG2(DBG_LIB, "insufficient number of octets to parse ASN.1 length"); return ASN1_INVALID_LENGTH; } /* read length field, skip tag and length */ n = blob->ptr[1]; *blob = chunk_skip(*blob, 2); if ((n & 0x80) == 0) { /* single length octet */ if (n > blob->len) { DBG2(DBG_LIB, "length is larger than remaining blob size"); return ASN1_INVALID_LENGTH; } return n; } /* composite length, determine number of length octets */ n &= 0x7f; if (n == 0 || n > blob->len) { DBG2(DBG_LIB, "number of length octets invalid"); return ASN1_INVALID_LENGTH; } if (n > sizeof(len)) { DBG2(DBG_LIB, "number of length octets is larger than limit of" " %d octets", (int)sizeof(len)); return ASN1_INVALID_LENGTH; } len = 0; while (n-- > 0) { len = 256*len + *blob->ptr++; blob->len--; } if (len > blob->len) { DBG2(DBG_LIB, "length is larger than remaining blob size"); return ASN1_INVALID_LENGTH; } return len; }
/** * check the presence of a pattern in a character string, skip if found */ static bool present(char* pattern, chunk_t* ch) { u_int len = strlen(pattern); if (ch->len >= len && strneq(ch->ptr, pattern, len)) { *ch = chunk_skip(*ch, len); return TRUE; } return FALSE; }
END_TEST /******************************************************************************* * chunk_skip[_zero] */ START_TEST(test_chunk_skip) { chunk_t foobar, a; foobar = chunk_from_str("foobar"); a = foobar; a = chunk_skip(a, 0); ck_assert(chunk_equals(a, foobar)); a = chunk_skip(a, 1); ck_assert(chunk_equals(a, chunk_from_str("oobar"))); a = chunk_skip(a, 2); ck_assert(chunk_equals(a, chunk_from_str("bar"))); a = chunk_skip(a, 3); assert_chunk_empty(a); a = foobar; a = chunk_skip(a, 6); assert_chunk_empty(a); a = foobar; a = chunk_skip(a, 10); assert_chunk_empty(a); }
/* * Defined in header. */ char *asn1_oid_to_string(chunk_t oid) { char buf[64], *pos = buf; int len; u_int val; if (!oid.len) { return NULL; } val = oid.ptr[0] / 40; len = snprintf(buf, sizeof(buf), "%u.%u", val, oid.ptr[0] - val * 40); oid = chunk_skip(oid, 1); if (len < 0 || len >= sizeof(buf)) { return NULL; } pos += len; val = 0; while (oid.len) { val = (val << 7) + (u_int)(oid.ptr[0] & 0x7f); if (oid.ptr[0] < 128) { len = snprintf(pos, sizeof(buf) + buf - pos, ".%u", val); if (len < 0 || len >= sizeof(buf) + buf - pos) { return NULL; } pos += len; val = 0; } oid = chunk_skip(oid, 1); } return (val == 0) ? strdup(buf) : NULL; }
/** * Described in header. */ void chunk_split(chunk_t chunk, const char *mode, ...) { va_list chunks; u_int len; chunk_t *ch; va_start(chunks, mode); while (TRUE) { if (*mode == '\0') { break; } len = va_arg(chunks, u_int); ch = va_arg(chunks, chunk_t*); /* a null chunk means skip len bytes */ if (ch == NULL) { chunk = chunk_skip(chunk, len); continue; } switch (*mode++) { case 'm': { ch->len = min(chunk.len, len); if (ch->len) { ch->ptr = chunk.ptr; } else { ch->ptr = NULL; } chunk = chunk_skip(chunk, ch->len); continue; } case 'a': { ch->len = min(chunk.len, len); if (ch->len) { ch->ptr = malloc(ch->len); memcpy(ch->ptr, chunk.ptr, ch->len); } else { ch->ptr = NULL; } chunk = chunk_skip(chunk, ch->len); continue; } case 'c': { ch->len = min(ch->len, chunk.len); ch->len = min(ch->len, len); if (ch->len) { memcpy(ch->ptr, chunk.ptr, ch->len); } else { ch->ptr = NULL; } chunk = chunk_skip(chunk, ch->len); continue; } default: break; } break; } va_end(chunks); }
/** * 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; }
static GstFlowReturn gst_smfdec_chain (GstPad * pad, GstBuffer * data) { GstSmfdec *dec = GST_SMFDEC (gst_pad_get_parent (pad)); gint i, ticks; guint len, midi_len; /* we must be negotiated */ g_assert ( dec != NULL ); g_assert (dec->buf_denom > 0); gst_adapter_push (dec->adapter, GST_BUFFER (data)); if (dec->chunk.fourcc) { chunk_ensure (dec->adapter, &dec->chunk, 0); } while (dec->chunk.fourcc || get_next_chunk (dec->adapter, &dec->chunk)) { switch (dec->chunk.fourcc) { case GST_MAKE_FOURCC ('M', 'T', 'h', 'd'): if (dec->format) { GST_ELEMENT_ERROR (dec, STREAM, DECODE, (NULL), ("got a header chunk while already initialized")); goto error; } if (dec->chunk.length != 6) { GST_ELEMENT_ERROR (dec, STREAM, DECODE, (NULL), ("header chunk %d bytes long, not 6", (int) dec->chunk.length)); goto error; } if (!chunk_ensure (dec->adapter, &dec->chunk, 6)) goto out; /* we add one, so we can use 0 for uninitialized */ dec->format = GST_READ_UINT16_BE (dec->chunk.data) + 1; if (dec->format > 2) g_warning ("I have no clue if midi format %u works", dec->format - 1); dec->tracks_missing = GST_READ_UINT16_BE (dec->chunk.data + 2); //g_assert (dec->tracks_missing == 1); /* ignore the number of track atoms */ i = (gint16) GST_READ_UINT16_BE (dec->chunk.data + 4); if (i < 0) { GST_ELEMENT_ERROR (dec, STREAM, NOT_IMPLEMENTED, (NULL), ("can't handle smpte timing")); goto error; } else { dec->start = 0; dec->division = i; } chunk_flush (dec->adapter, &dec->chunk); break; case GST_MAKE_FOURCC ('M', 'T', 'r', 'k'): if (dec->format == 0) { GST_ELEMENT_ERROR (dec, STREAM, DECODE, (NULL), ("got a track chunk while not yet initialized")); goto error; } /* figure out if we have enough data */ ticks = gst_midi_data_parse_varlen (dec->chunk.data, dec->chunk.available, &len); if (ticks == -1) goto out; if (ticks == -2) { GST_ELEMENT_ERROR (dec, STREAM, DECODE, (NULL), ("invalid delta time value")); goto error; } midi_len = gst_midi_data_get_length (dec->chunk.data + len, dec->chunk.available - len, dec->status); if (midi_len == 0) goto out; /* we have enough data, process */ dec->ticks += ticks; //g_print ("got %u ticks, now %u\n", ticks, dec->ticks); if (dec->chunk.data[len] & 0x80) { dec->status = dec->chunk.data[len]; len++; midi_len--; } if (dec->status == 0xFF) { if (!gst_smfdec_meta_event (dec, dec->chunk.data + len, midi_len)) goto error; } else { gst_smfdec_buffer_append (dec, dec->status, dec->chunk.data + len, midi_len); } chunk_skip (dec->adapter, &dec->chunk, len + midi_len); if (dec->chunk.length == 0) chunk_clear (&dec->chunk); break; default: goto out; } } out: gst_object_unref(dec); return GST_FLOW_OK;; error: gst_smfdec_reset (dec); return GST_FLOW_ERROR; }