Ejemplo n.º 1
0
/**
 * load the credential from a blob
 */
static void *load_from_blob(chunk_t blob, credential_type_t type, int subtype,
							chunk_t(*cb)(void*,int), void *cb_data,
							x509_flag_t flags)
{
	void *cred = NULL;
	bool pgp = FALSE;

	blob = chunk_clone(blob);
	if (!is_asn1(blob))
	{
		if (pem_to_bin(&blob, cb, cb_data, &pgp) != SUCCESS)
		{
			chunk_clear(&blob);
			return NULL;
		}
		if (pgp && type == CRED_PRIVATE_KEY)
		{
			/* PGP encoded keys are parsed with a KEY_ANY key type, as it
			 * can contain any type of key. However, ipsec.secrets uses
			 * RSA for PGP keys, which is actually wrong. */
			subtype = KEY_ANY;
		}
	}
	/* if CERT_ANY is given, ASN1 encoded blob is handled as X509 */
	if (type == CRED_CERTIFICATE && subtype == CERT_ANY)
	{
		subtype = pgp ? CERT_GPG : CERT_X509;
	}
	cred = lib->creds->create(lib->creds, type, subtype,
							  pgp ? BUILD_BLOB_PGP : BUILD_BLOB_ASN1_DER, blob,
							  flags ? BUILD_X509_FLAG : BUILD_END,
							  flags, BUILD_END);
	chunk_clear(&blob);
	return cred;
}
Ejemplo n.º 2
0
/**
 * Try to decrypt the given blob with multiple passwords using the given
 * pkcs5 object.
 */
static private_key_t *decrypt_private_key(pkcs5_t *pkcs5, chunk_t blob)
{
	enumerator_t *enumerator;
	shared_key_t *shared;
	private_key_t *private_key = NULL;

	enumerator = lib->credmgr->create_shared_enumerator(lib->credmgr,
										SHARED_PRIVATE_KEY_PASS, NULL, NULL);
	while (enumerator->enumerate(enumerator, &shared, NULL, NULL))
	{
		chunk_t decrypted;

		if (!pkcs5->decrypt(pkcs5, shared->get_key(shared), blob, &decrypted))
		{
			continue;
		}
		private_key = parse_private_key(decrypted);
		if (private_key)
		{
			chunk_clear(&decrypted);
			break;
		}
		chunk_free(&decrypted);
	}
	enumerator->destroy(enumerator);

	return private_key;
}
Ejemplo n.º 3
0
/*
 * Described in header
 */
bool botan_dh_key_derivation(botan_privkey_t key, chunk_t pub, chunk_t *secret)
{
	botan_pk_op_ka_t ka;

	if (botan_pk_op_key_agreement_create(&ka, key, "Raw", 0))
	{
		return FALSE;
	}

	if (botan_pk_op_key_agreement_size(ka, &secret->len))
	{
		botan_pk_op_key_agreement_destroy(ka);
		return FALSE;
	}

	*secret = chunk_alloc(secret->len);
	if (botan_pk_op_key_agreement(ka, secret->ptr, &secret->len, pub.ptr,
								  pub.len, NULL, 0))
	{
		chunk_clear(secret);
		botan_pk_op_key_agreement_destroy(ka);
		return FALSE;
	}
	botan_pk_op_key_agreement_destroy(ka);
	return TRUE;
}
Ejemplo n.º 4
0
static void
chunk_flush (GstAdapter *adapter, Chunk *chunk)
{
  g_return_if_fail (chunk->available == chunk->length);
  
  gst_adapter_flush (adapter, chunk->length);
  chunk_clear (chunk);
}
Ejemplo n.º 5
0
/*
 * Described in header.
 */
bool rng_allocate_bytes_not_zero(rng_t *rng, size_t len, chunk_t *chunk,
								 bool all)
{
	*chunk = chunk_alloc(len);
	if (!rng_get_bytes_not_zero(rng, len, chunk->ptr, all))
	{
		chunk_clear(chunk);
		return FALSE;
	}
	return TRUE;
}
Ejemplo n.º 6
0
END_TEST

START_TEST(test_newhope_ke_wrong)
{
    chunk_t i_msg, r_msg, i_shared_secret, r_shared_secret;
    diffie_hellman_t *i_nh, *r_nh;

    i_nh = lib->crypto->create_dh(lib->crypto, NH_128_BIT);
    ck_assert(i_nh != NULL);
    ck_assert(i_nh->get_my_public_value(i_nh, &i_msg));

    r_nh = lib->crypto->create_dh(lib->crypto, NH_128_BIT);
    ck_assert(r_nh != NULL);
    ck_assert(r_nh->set_other_public_value(r_nh, i_msg));
    ck_assert(r_nh->get_my_public_value(r_nh, &r_msg));

    /* destroy 1st instance of i_nh */
    i_nh->destroy(i_nh);
    chunk_free(&i_msg);

    /* create 2nd instance of i_nh */
    i_nh = lib->crypto->create_dh(lib->crypto, NH_128_BIT);
    ck_assert(i_nh != NULL);
    ck_assert(i_nh->get_my_public_value(i_nh, &i_msg));
    ck_assert(i_nh->set_other_public_value(i_nh, r_msg));

    ck_assert(r_nh->get_shared_secret(r_nh, &r_shared_secret));
    ck_assert(i_nh->get_shared_secret(i_nh, &i_shared_secret));
    ck_assert(!chunk_equals(i_shared_secret, r_shared_secret));

    /* cleanup */
    chunk_clear(&i_shared_secret);
    chunk_clear(&r_shared_secret);
    chunk_free(&i_msg);
    chunk_free(&r_msg);
    i_nh->destroy(i_nh);
    r_nh->destroy(r_nh);
}
Ejemplo n.º 7
0
END_TEST

/*******************************************************************************
 * clear
 */

START_TEST(test_chunk_clear)
{
	chunk_t chunk;
	u_char *ptr;
	int i;
	bool cleared = TRUE;

	chunk = chunk_empty;
	chunk_clear(&chunk);
	chunk_free(&chunk);

	chunk = chunk_alloc(64);
	ptr = chunk.ptr;
	for (i = 0; i < 64; i++)
	{
		chunk.ptr[i] = i;
	}
	chunk_clear(&chunk);
	/* check memory area of freed chunk. We can't use ck_assert() for this
	 * test directly, as it might allocate data at the freed area. */
	for (i = 0; i < 64; i++)
	{
		if (ptr[i] != 0 && ptr[i] == i)
		{
			cleared = FALSE;
			break;
		}
	}
	assert_chunk_empty(chunk);
	ck_assert(cleared);
}
Ejemplo n.º 8
0
static void
gst_smfdec_reset (GstSmfdec *dec)
{
  gst_adapter_clear (dec->adapter);
  chunk_clear (&dec->chunk);
  dec->format = 0;
  dec->start = 0;
  dec->status = 0;
  dec->division = 1;
  dec->ticks = 0;
  dec->buf_start = 0;
  dec->buf_num=1024;
  dec->buf_denom=44100;
  dec->buf_sent = 0;
  gst_smfdec_set_tempo (dec, 480000);
}
Ejemplo n.º 9
0
/**
 * Described in header.
 */
chunk_t chunk_create_cat(u_char *ptr, const char* mode, ...)
{
	va_list chunks;
	chunk_t construct = chunk_create(ptr, 0);

	va_start(chunks, mode);
	while (TRUE)
	{
		bool free_chunk = FALSE, clear_chunk = FALSE;
		chunk_t ch;

		switch (*mode++)
		{
			case 's':
				clear_chunk = TRUE;
				/* FALL */
			case 'm':
				free_chunk = TRUE;
				/* FALL */
			case 'c':
				ch = va_arg(chunks, chunk_t);
				memcpy(ptr, ch.ptr, ch.len);
				ptr += ch.len;
				construct.len += ch.len;
				if (clear_chunk)
				{
					chunk_clear(&ch);
				}
				else if (free_chunk)
				{
					free(ch.ptr);
				}
				continue;
			default:
				break;
		}
		break;
	}
	va_end(chunks);

	return construct;
}
Ejemplo n.º 10
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;
}
Ejemplo n.º 11
0
/**
 * create a symmetrically encrypted pkcs7 contentInfo object
 */
chunk_t pkcs7_build_envelopedData(chunk_t data, certificate_t *cert, int enc_alg)
{
	encryption_algorithm_t alg;
	size_t alg_key_size;
	chunk_t symmetricKey, protectedKey, iv, in, out;
	crypter_t *crypter;

	alg = encryption_algorithm_from_oid(enc_alg, &alg_key_size);
	crypter = lib->crypto->create_crypter(lib->crypto, alg,
										  alg_key_size/BITS_PER_BYTE);
	if (crypter == NULL)
	{
		DBG1(DBG_LIB, "crypter for %N not available", encryption_algorithm_names, alg);
		return chunk_empty;
	}

	/* generate a true random symmetric encryption key and a pseudo-random iv */
	{
		rng_t *rng;

		rng = lib->crypto->create_rng(lib->crypto, RNG_TRUE);
		rng->allocate_bytes(rng, crypter->get_key_size(crypter), &symmetricKey);
		DBG4(DBG_LIB, "symmetric encryption key %B", &symmetricKey);
		rng->destroy(rng);

		rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
		rng->allocate_bytes(rng, crypter->get_iv_size(crypter), &iv);
		DBG4(DBG_LIB, "initialization vector: %B", &iv);
		rng->destroy(rng);
	}

	/* pad the data to a multiple of the block size */
	{
		size_t block_size = crypter->get_block_size(crypter);
		size_t padding = block_size - data.len % block_size;

		in.len = data.len + padding;
		in.ptr = malloc(in.len);

		DBG2(DBG_LIB, "padding %u bytes of data to multiple block size of %u bytes",
			 data.len, in.len);

		/* copy data */
		memcpy(in.ptr, data.ptr, data.len);
		/* append padding */
		memset(in.ptr + data.len, padding, padding);
	}
	DBG3(DBG_LIB, "padded unencrypted data %B", &in);

	/* symmetric encryption of data object */
	crypter->set_key(crypter, symmetricKey);
	crypter->encrypt(crypter, in, iv, &out);
	crypter->destroy(crypter);
	chunk_clear(&in);
    DBG3(DBG_LIB, "encrypted data %B", &out);

	/* protect symmetric key by public key encryption */
	{
		public_key_t *key = cert->get_public_key(cert);

		if (key == NULL)
		{
			DBG1(DBG_LIB, "public key not found in encryption certificate");
			chunk_clear(&symmetricKey);
			chunk_free(&iv);
			chunk_free(&out);
			return chunk_empty;
		}
		key->encrypt(key, ENCRYPT_RSA_PKCS1, symmetricKey, &protectedKey);
		key->destroy(key);
	}

	/* build pkcs7 enveloped data object */
	{

		chunk_t contentEncryptionAlgorithm = asn1_wrap(ASN1_SEQUENCE, "mm"
					, asn1_build_known_oid(enc_alg)
					, asn1_simple_object(ASN1_OCTET_STRING, iv));

		chunk_t encryptedContentInfo = asn1_wrap(ASN1_SEQUENCE, "mmm"
					, asn1_build_known_oid(OID_PKCS7_DATA)
					, contentEncryptionAlgorithm
					, asn1_wrap(ASN1_CONTEXT_S_0, "m", out));

		chunk_t encryptedKey = asn1_wrap(ASN1_OCTET_STRING, "m"
					, protectedKey);

		chunk_t recipientInfo = asn1_wrap(ASN1_SEQUENCE, "cmmm"
					, ASN1_INTEGER_0
					, pkcs7_build_issuerAndSerialNumber(cert)
					, asn1_algorithmIdentifier(OID_RSA_ENCRYPTION)
					, encryptedKey);

		chunk_t cInfo;
		contentInfo_t envelopedData;

		envelopedData.type = OID_PKCS7_ENVELOPED_DATA;
		envelopedData.content = asn1_wrap(ASN1_SEQUENCE, "cmm"
					, ASN1_INTEGER_0
					, asn1_wrap(ASN1_SET, "m", recipientInfo)
					, encryptedContentInfo);

		cInfo = pkcs7_build_contentInfo(&envelopedData);
		DBG3(DBG_LIB, "envelopedData %B", &cInfo);

		chunk_free(&envelopedData.content);
		chunk_free(&iv);
		chunk_clear(&symmetricKey);
		return cInfo;
	}
}
Ejemplo n.º 12
0
/**
 * Parse a PKCS#7 envelopedData object
 */
bool pkcs7_parse_envelopedData(chunk_t blob, chunk_t *data,
							   chunk_t serialNumber,
							   private_key_t *key)
{
	asn1_parser_t *parser;
	chunk_t object;
	chunk_t iv                = chunk_empty;
	chunk_t symmetric_key     = chunk_empty;
	chunk_t encrypted_content = chunk_empty;

	crypter_t *crypter = NULL;

	int enc_alg         = OID_UNKNOWN;
	int content_enc_alg = OID_UNKNOWN;
	int version;
	int objectID;
	bool success = FALSE;

	contentInfo_t cInfo = empty_contentInfo;
	*data = chunk_empty;

	if (!pkcs7_parse_contentInfo(blob, 0, &cInfo))
	{
		goto failed;
	}
	if (cInfo.type != OID_PKCS7_ENVELOPED_DATA)
	{
		DBG1(DBG_LIB, "pkcs7 content type is not envelopedData");
		goto failed;
	}

	parser = asn1_parser_create(envelopedDataObjects, cInfo.content);
	parser->set_top_level(parser, 2);

	while (parser->iterate(parser, &objectID, &object))
	{
		u_int level = parser->get_level(parser);

		switch (objectID)
		{
		case PKCS7_ENVELOPED_VERSION:
			version = object.len ? (int)*object.ptr : 0;
			DBG2(DBG_LIB, "  v%d", version);
			if (version != 0)
			{
				DBG1(DBG_LIB, "envelopedData version is not 0");
				goto end;
			}
			break;
		case PKCS7_RECIPIENT_INFO_VERSION:
			version = object.len ? (int)*object.ptr : 0;
			DBG2(DBG_LIB, "  v%d", version);
			if (version != 0)
			{
				DBG1(DBG_LIB, "recipient info version is not 0");
				goto end;
			}
			break;
		case PKCS7_ISSUER:
			{
				identification_t *issuer = identification_create_from_encoding(
													ID_DER_ASN1_DN, object);
				DBG2(DBG_LIB, "  \"%Y\"", issuer);
				issuer->destroy(issuer);
				break;
			}
		case PKCS7_SERIAL_NUMBER:
			if (!chunk_equals(serialNumber, object))
			{
				DBG1(DBG_LIB, "serial numbers do not match");
				goto end;
			}
			break;
		case PKCS7_ENCRYPTION_ALG:
			enc_alg = asn1_parse_algorithmIdentifier(object, level, NULL);
			if (enc_alg != OID_RSA_ENCRYPTION)
			{
				DBG1(DBG_LIB, "only rsa encryption supported");
				goto end;
			}
			break;
		case PKCS7_ENCRYPTED_KEY:
			if (!key->decrypt(key, ENCRYPT_RSA_PKCS1, object, &symmetric_key))
			{
				DBG1(DBG_LIB, "symmetric key could not be decrypted with rsa");
				goto end;
			}
			DBG4(DBG_LIB, "symmetric key %B", &symmetric_key);
			break;
		case PKCS7_CONTENT_TYPE:
			if (asn1_known_oid(object) != OID_PKCS7_DATA)
			{
				 DBG1(DBG_LIB, "encrypted content not of type pkcs7 data");
				 goto end;
			}
			break;
		case PKCS7_CONTENT_ENC_ALGORITHM:
			content_enc_alg = asn1_parse_algorithmIdentifier(object, level, &iv);

			if (content_enc_alg == OID_UNKNOWN)
			{
				DBG1(DBG_LIB, "unknown content encryption algorithm");
				goto end;
			}
			if (!asn1_parse_simple_object(&iv, ASN1_OCTET_STRING, level+1, "IV"))
			{
				DBG1(DBG_LIB, "IV could not be parsed");
				goto end;
			}
			break;
		case PKCS7_ENCRYPTED_CONTENT:
			encrypted_content = object;
			break;
		}
	}
	success = parser->success(parser);

end:
	parser->destroy(parser);
	if (!success)
	{
		goto failed;
	}
	success = FALSE;

	/* decrypt the content */
	{
		encryption_algorithm_t alg;
		size_t key_size;
		crypter_t *crypter;

		alg = encryption_algorithm_from_oid(content_enc_alg, &key_size);
		if (alg == ENCR_UNDEFINED)
		{
			DBG1(DBG_LIB, "unsupported content encryption algorithm");
			goto failed;
		}
		crypter = lib->crypto->create_crypter(lib->crypto, alg, key_size);
		if (crypter == NULL)
		{
			DBG1(DBG_LIB, "crypter %N not available", encryption_algorithm_names, alg);
			goto failed;
		}
		if (symmetric_key.len != crypter->get_key_size(crypter))
		{
			DBG1(DBG_LIB, "symmetric key length %d is wrong", symmetric_key.len);
			goto failed;
		}
		if (iv.len != crypter->get_iv_size(crypter))
		{
			DBG1(DBG_LIB, "IV length %d is wrong", iv.len);
			goto failed;
		}
		crypter->set_key(crypter, symmetric_key);
		crypter->decrypt(crypter, encrypted_content, iv, data);
		DBG4(DBG_LIB, "decrypted content with padding: %B", data);
	}

	/* remove the padding */
	{
		u_char *pos = data->ptr + data->len - 1;
		u_char pattern = *pos;
		size_t padding = pattern;

		if (padding > data->len)
		{
			DBG1(DBG_LIB, "padding greater than data length");
			goto failed;
		}
		data->len -= padding;

		while (padding-- > 0)
		{
			if (*pos-- != pattern)
			{
				DBG1(DBG_LIB, "wrong padding pattern");
				goto failed;
			}
		}
	}
	success = TRUE;

failed:
	DESTROY_IF(crypter);
	chunk_clear(&symmetric_key);
	if (!success)
	{
		free(data->ptr);
	}
	return success;
}
Ejemplo n.º 13
0
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;
}