summaryrefslogtreecommitdiff
path: root/src/tspi/tspi_asn1.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/tspi/tspi_asn1.c')
-rw-r--r--src/tspi/tspi_asn1.c255
1 files changed, 255 insertions, 0 deletions
diff --git a/src/tspi/tspi_asn1.c b/src/tspi/tspi_asn1.c
new file mode 100644
index 0000000..f17ce41
--- /dev/null
+++ b/src/tspi/tspi_asn1.c
@@ -0,0 +1,255 @@
+
+/*
+ * Licensed Materials - Property of IBM
+ *
+ * trousers - An open source TCG Software Stack
+ *
+ * (C) Copyright International Business Machines Corp. 2007
+ *
+ */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <openssl/asn1.h>
+#include <openssl/asn1t.h>
+
+#ifndef TSS_BUILD_ASN1_OPENSSL
+#include <arpa/inet.h>
+#endif
+
+#include "trousers/tss.h"
+#include "trousers/trousers.h"
+#include "trousers_types.h"
+#include "tsplog.h"
+
+#define TSS_OPENSSL_ASN1_ERROR (0xffffffff)
+
+#if (OPENSSL_VERSION_NUMBER >= 0x0090800FL)
+#define OPENSSL_COMPAT_CONST const
+#else
+#define OPENSSL_COMPAT_CONST
+#endif
+
+#define OPENSSL_COMPAT_ASN1_SEQUENCE(tname) \
+ static const ASN1_TEMPLATE tname##_seq_tt[]
+
+typedef struct tdTSS_BLOB {
+ ASN1_INTEGER * structVersion;
+ ASN1_INTEGER * blobType;
+ ASN1_INTEGER * blobLength;
+ ASN1_OCTET_STRING * blob;
+} TSS_BLOB;
+
+OPENSSL_COMPAT_ASN1_SEQUENCE(TSS_BLOB) = {
+ ASN1_SIMPLE(TSS_BLOB, structVersion, ASN1_INTEGER),
+ ASN1_SIMPLE(TSS_BLOB, blobType, ASN1_INTEGER),
+ ASN1_SIMPLE(TSS_BLOB, blobLength, ASN1_INTEGER),
+ ASN1_SIMPLE(TSS_BLOB, blob, ASN1_OCTET_STRING)
+} ASN1_SEQUENCE_END(TSS_BLOB)
+IMPLEMENT_ASN1_FUNCTIONS(TSS_BLOB)
+
+
+TSS_RESULT
+Tspi_EncodeDER_TssBlob(UINT32 rawBlobSize, /* in */
+ BYTE *rawBlob, /* in */
+ UINT32 blobType, /* in */
+ UINT32 *derBlobSize, /* in/out */
+ BYTE *derBlob) /* out */
+{
+#ifdef TSS_BUILD_ASN1_OPENSSL
+ TSS_BLOB *tssBlob = NULL;
+#endif
+ BYTE *encBlob = NULL;
+ UINT32 encBlobLen;
+
+ if ((rawBlobSize == 0) || (rawBlob == NULL))
+ return TSPERR(TSS_E_BAD_PARAMETER);
+
+ if ((blobType < TSS_BLOB_TYPE_KEY) || (blobType > TSS_BLOB_TYPE_CMK_BYTE_STREAM))
+ return TSPERR(TSS_E_BAD_PARAMETER);
+
+ if ((*derBlobSize != 0) && (derBlob == NULL))
+ return TSPERR(TSS_E_BAD_PARAMETER);
+
+ /* The TSS working group has stated that the ASN1 encoding will be done in a
+ * specific way that generates an ASN1 encoding that is exactly 20 bytes
+ * larger than the blob being encoded.
+ *
+ * OpenSSL uses the smallest number of bytes possible to encode and object
+ * and as a result cannot be used to perform the encoding. The encoding
+ * must be done manually.
+ *
+ * The 20 byte fixed header will result in issues for objects greater than
+ * 2^16 in size since some fields are now limited to 16-bit lengths.
+ */
+
+#ifdef TSS_BUILD_ASN1_OPENSSL
+ tssBlob = TSS_BLOB_new();
+ if (!tssBlob)
+ return TSPERR(TSS_E_OUTOFMEMORY);
+
+ if (ASN1_INTEGER_set(tssBlob->structVersion, TSS_BLOB_STRUCT_VERSION) == 0) {
+ TSS_BLOB_free(tssBlob);
+ return TSPERR(TSS_E_OUTOFMEMORY);
+ }
+
+ if (ASN1_INTEGER_set(tssBlob->blobType, blobType) == 0) {
+ TSS_BLOB_free(tssBlob);
+ return TSPERR(TSS_E_OUTOFMEMORY);
+ }
+
+ if (ASN1_INTEGER_set(tssBlob->blobLength, rawBlobSize) == 0) {
+ TSS_BLOB_free(tssBlob);
+ return TSPERR(TSS_E_OUTOFMEMORY);
+ }
+
+ if (ASN1_OCTET_STRING_set(tssBlob->blob, rawBlob, rawBlobSize) == 0) {
+ TSS_BLOB_free(tssBlob);
+ return TSPERR(TSS_E_OUTOFMEMORY);
+ }
+
+ encBlobLen = i2d_TSS_BLOB(tssBlob, &encBlob);
+ if (encBlobLen <= 0) {
+ TSS_BLOB_free(tssBlob);
+ return TSPERR(TSS_E_INTERNAL_ERROR);
+ }
+
+ if (*derBlobSize != 0) {
+ if (encBlobLen <= *derBlobSize) {
+ memcpy(derBlob, encBlob, encBlobLen);
+ }
+ else {
+ OPENSSL_free(encBlob);
+ TSS_BLOB_free(tssBlob);
+ return TSPERR(TSS_E_BAD_PARAMETER);
+ }
+ }
+
+ *derBlobSize = encBlobLen;
+
+ OPENSSL_free(encBlob);
+ TSS_BLOB_free(tssBlob);
+#else
+ if ((rawBlobSize + 16) > UINT16_MAX)
+ return TSPERR(TSS_E_INTERNAL_ERROR);
+
+ encBlobLen = rawBlobSize + 20;
+
+ if (*derBlobSize != 0) {
+ if (encBlobLen <= *derBlobSize) {
+ UINT16 *pShort;
+ UINT32 *pLong;
+
+ encBlob = derBlob;
+ encBlob[0] = 0x30; /* Sequence tag */
+ encBlob[1] = 0x82; /* Length in the two octets that follow */
+ encBlob += 2;
+ pShort = (UINT16 *)encBlob;
+ *pShort = htons(rawBlobSize + 16);
+ encBlob += sizeof(UINT16);
+
+ encBlob[0] = 0x02; /* Integer tag */
+ encBlob[1] = 0x01; /* Length is one */
+ encBlob[2] = (BYTE)TSS_BLOB_STRUCT_VERSION;
+ encBlob += 3;
+
+ encBlob[0] = 0x02; /* Integer tag */
+ encBlob[1] = 0x01; /* Length is one */
+ encBlob[2] = (BYTE)blobType;
+ encBlob += 3;
+
+ encBlob[0] = 0x02; /* Integer tag */
+ encBlob[1] = 0x04; /* Length is four */
+ encBlob += 2;
+ pLong = (UINT32 *)encBlob;
+ *pLong = htonl(rawBlobSize);
+ encBlob += sizeof(UINT32);
+
+ encBlob[0] = 0x04; /* Octet string tag */
+ encBlob[1] = 0x82; /* Length in the two octets that follow */
+ encBlob += 2;
+ pShort = (UINT16 *)encBlob;
+ *pShort = htons(rawBlobSize);
+ encBlob += sizeof(UINT16);
+ memcpy(encBlob, rawBlob, rawBlobSize);
+ }
+ else
+ return TSPERR(TSS_E_BAD_PARAMETER);
+ }
+
+ *derBlobSize = encBlobLen;
+#endif
+
+ return TSS_SUCCESS;
+}
+
+TSS_RESULT
+Tspi_DecodeBER_TssBlob(UINT32 berBlobSize, /* in */
+ BYTE *berBlob, /* in */
+ UINT32 *blobType, /* out */
+ UINT32 *rawBlobSize, /* in/out */
+ BYTE *rawBlob) /* out */
+{
+ TSS_BLOB *tssBlob = NULL;
+ OPENSSL_COMPAT_CONST BYTE *encBlob = berBlob;
+
+ UINT32 encBlobLen = berBlobSize;
+ UINT32 decStructVersion, decBlobType, decBlobSize;
+
+ if ((berBlobSize == 0) || (berBlob == NULL))
+ return TSPERR(TSS_E_BAD_PARAMETER);
+
+ if ((*rawBlobSize != 0) && (rawBlob == NULL))
+ return TSPERR(TSS_E_BAD_PARAMETER);
+
+ tssBlob = d2i_TSS_BLOB(NULL, &encBlob, encBlobLen);
+ if (!tssBlob)
+ return TSPERR(TSS_E_INTERNAL_ERROR);
+
+ decStructVersion = ASN1_INTEGER_get(tssBlob->structVersion);
+ if (decStructVersion == TSS_OPENSSL_ASN1_ERROR) {
+ TSS_BLOB_free(tssBlob);
+ return TSPERR(TSS_E_INTERNAL_ERROR);
+ }
+ if (decStructVersion > TSS_BLOB_STRUCT_VERSION) {
+ TSS_BLOB_free(tssBlob);
+ return TSPERR(TSS_E_BAD_PARAMETER);
+ }
+
+ decBlobType = ASN1_INTEGER_get(tssBlob->blobType);
+ if (decBlobType == TSS_OPENSSL_ASN1_ERROR) {
+ TSS_BLOB_free(tssBlob);
+ return TSPERR(TSS_E_INTERNAL_ERROR);
+ }
+ if ((decBlobType < TSS_BLOB_TYPE_KEY) || (decBlobType > TSS_BLOB_TYPE_CMK_BYTE_STREAM)) {
+ TSS_BLOB_free(tssBlob);
+ return TSPERR(TSS_E_BAD_PARAMETER);
+ }
+
+ decBlobSize = ASN1_INTEGER_get(tssBlob->blobLength);
+ if (decBlobSize == TSS_OPENSSL_ASN1_ERROR) {
+ TSS_BLOB_free(tssBlob);
+ return TSPERR(TSS_E_INTERNAL_ERROR);
+ }
+
+ if (*rawBlobSize != 0) {
+ if (decBlobSize <= *rawBlobSize) {
+ memcpy(rawBlob, tssBlob->blob->data, decBlobSize);
+ }
+ else {
+ TSS_BLOB_free(tssBlob);
+ return TSPERR(TSS_E_BAD_PARAMETER);
+ }
+ }
+
+ *rawBlobSize = decBlobSize;
+ *blobType = decBlobType;
+
+ TSS_BLOB_free(tssBlob);
+
+ return TSS_SUCCESS;
+}
+