| /* |
| * Copyright (c) 2013 .SE (The Internet Infrastructure Foundation) |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
| * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
| * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE |
| * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER |
| * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
| * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN |
| * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| /***************************************************************************** |
| softhsm2-dump-file.cpp |
| |
| This program can be used for dumping SoftHSM v2 object files. |
| *****************************************************************************/ |
| |
| #include <config.h> |
| |
| #include "common.h" |
| |
| // Attribute types on disk |
| #define BOOLEAN_ATTR 0x1 |
| #define ULONG_ATTR 0x2 |
| #define BYTES_ATTR 0x3 |
| #define ATTRMAP_ATTR 0x4 |
| #define MECHSET_ATTR 0x5 |
| |
| // Maximum byte string length (1Gib) |
| #define MAX_BYTES 0x3fffffff |
| |
| typedef AttributeTK<uint64_t, uint64_t, uint64_t> Attribute; |
| |
| // Attribute specialization |
| template<> |
| bool Attribute::isBoolean() const |
| { |
| return kind == BOOLEAN_ATTR; |
| } |
| |
| template<> |
| bool Attribute::isInteger() const |
| { |
| return kind == ULONG_ATTR; |
| } |
| |
| template<> |
| bool Attribute::isBinary() const |
| { |
| return kind == BYTES_ATTR; |
| } |
| |
| template<> |
| bool Attribute::isMechSet() const |
| { |
| return kind == MECHSET_ATTR; |
| } |
| |
| template<> |
| void Attribute::dumpType() const |
| { |
| dumpULong(type, true); |
| } |
| |
| template<> |
| void Attribute::dumpKind() const |
| { |
| dumpULong(kind, true); |
| } |
| |
| template<> |
| void Attribute::dumpBoolValue() const |
| { |
| dumpBool(boolValue, true); |
| } |
| |
| template<> |
| void Attribute::dumpULongValue(uint64_t value) const |
| { |
| dumpULong(value, true); |
| } |
| |
| // dumpMap specialization |
| typedef std::vector<Attribute> va_type; |
| |
| void dumpMap(const va_type& value) |
| { |
| for (va_type::const_iterator attr = value.begin(); attr != value.end(); ++attr) |
| attr->dump(); |
| } |
| |
| // Read a boolean (in fact unsigned 8 bit long) value |
| bool readBool(FILE* stream, uint8_t& value) |
| { |
| value = 0; |
| fpos_t pos; |
| if (fgetpos(stream, &pos) != 0) |
| { |
| return false; |
| } |
| uint8_t v; |
| if (fread(&v, 1, 1, stream) != 1) |
| { |
| (void) fsetpos(stream, &pos); |
| return false; |
| } |
| value = v; |
| return true; |
| } |
| |
| // Read an unsigned 64 bit long value |
| bool readULong(FILE* stream, uint64_t& value) |
| { |
| value = 0; |
| fpos_t pos; |
| if (fgetpos(stream, &pos) != 0) |
| { |
| return false; |
| } |
| uint8_t v[8]; |
| if (fread(v, 1, 8, stream) != 8) |
| { |
| (void) fsetpos(stream, &pos); |
| return false; |
| } |
| for (size_t i = 0; i < 8; i++) |
| { |
| value <<= 8; |
| value += v[i]; |
| } |
| return true; |
| } |
| |
| // Read a byte string (aka uint8_t vector) value |
| bool readBytes(FILE* stream, std::vector<uint8_t>& value) |
| { |
| size_t len = value.size(); |
| fpos_t pos; |
| if (fgetpos(stream, &pos) != 0) |
| { |
| return false; |
| } |
| if (fread(&value[0], 1, len, stream) != len) |
| { |
| (void) fsetpos(stream, &pos); |
| return false; |
| } |
| return true; |
| } |
| |
| // Read a map (aka Attribute vector) value |
| bool readMap(FILE* stream, uint64_t len, std::vector<Attribute>& value) |
| { |
| fpos_t pos; |
| if (fgetpos(stream, &pos) != 0) |
| { |
| return false; |
| } |
| while (len != 0) |
| { |
| Attribute attr; |
| |
| if (len < 8) |
| { |
| (void) fsetpos(stream, &pos); |
| return false; |
| } |
| if (!readULong(stream, attr.type)) |
| { |
| (void) fsetpos(stream, &pos); |
| return false; |
| } |
| len -= 8; |
| |
| if (len < 8) |
| { |
| (void) fsetpos(stream, &pos); |
| return false; |
| } |
| if (!readULong(stream, attr.kind)) |
| { |
| (void) fsetpos(stream, &pos); |
| return false; |
| } |
| len -= 8; |
| |
| if (attr.kind == BOOLEAN_ATTR) |
| { |
| if (len < 1) |
| { |
| (void) fsetpos(stream, &pos); |
| return false; |
| } |
| len -= 1; |
| if (!readBool(stream, attr.boolValue)) |
| { |
| (void) fsetpos(stream, &pos); |
| return false; |
| } |
| } |
| else if (attr.kind == ULONG_ATTR) |
| { |
| if (len < 8) |
| { |
| (void) fsetpos(stream, &pos); |
| return false; |
| } |
| if (!readULong(stream, attr.ulongValue)) |
| { |
| (void) fsetpos(stream, &pos); |
| return false; |
| } |
| len -= 8; |
| } |
| else if (attr.kind == BYTES_ATTR) |
| { |
| uint64_t size; |
| if (len < 8) |
| { |
| (void) fsetpos(stream, &pos); |
| return false; |
| } |
| if (!readULong(stream, size)) |
| { |
| (void) fsetpos(stream, &pos); |
| return false; |
| } |
| len -= 8; |
| |
| if (len < size) |
| { |
| (void) fsetpos(stream, &pos); |
| return false; |
| } |
| attr.bytestrValue.resize((size_t)size); |
| if (!readBytes(stream, attr.bytestrValue)) |
| { |
| (void) fsetpos(stream, &pos); |
| return false; |
| } |
| len -= size; |
| } |
| else if (attr.kind == MECHSET_ATTR) |
| { |
| uint64_t size; |
| if (len < 8) |
| { |
| (void) fsetpos(stream, &pos); |
| return false; |
| } |
| if (!readULong(stream, size)) |
| { |
| (void) fsetpos(stream, &pos); |
| return false; |
| } |
| len -= 8; |
| |
| if (len < size * 8) |
| { |
| (void) fsetpos(stream, &pos); |
| return false; |
| } |
| |
| for (unsigned long i = 0; i < size; i++) |
| { |
| uint64_t mech; |
| if (!readULong(stream, mech)) |
| { |
| (void) fsetpos(stream, &pos); |
| return false; |
| } |
| attr.mechSetValue.insert(mech); |
| } |
| len -= size * 8; |
| } |
| else |
| { |
| (void) fsetpos(stream, &pos); |
| return false; |
| } |
| |
| value.push_back(attr); |
| } |
| |
| return true; |
| } |
| |
| // Error case |
| void corrupt(FILE* stream) |
| { |
| uint8_t v; |
| for (size_t i = 0; i < 8; i++) |
| { |
| if (fread(&v, 1, 1, stream) != 1) |
| { |
| if (ferror(stream)) |
| { |
| printf("get an error...\n"); |
| } |
| return; |
| } |
| if (i != 0) |
| { |
| printf(" "); |
| } |
| printf("%02hhx", v); |
| } |
| if (fread(&v, 1, 1, stream) != 1) |
| { |
| if (ferror(stream)) |
| { |
| printf("\nget an error...\n"); |
| } |
| return; |
| } |
| printf("...\n"); |
| } |
| |
| // Core function |
| void dump(FILE* stream) |
| { |
| uint64_t gen; |
| if (!readULong(stream, gen)) |
| { |
| if (feof(stream)) |
| { |
| printf("empty file\n"); |
| } |
| else |
| { |
| corrupt(stream); |
| } |
| return; |
| } |
| dumpULong(gen); |
| printf("generation %lu\n", (unsigned long) gen); |
| |
| while (!feof(stream)) |
| { |
| uint64_t p11type; |
| if (!readULong(stream, p11type)) |
| { |
| corrupt(stream); |
| return; |
| } |
| dumpULong(p11type); |
| if ((uint64_t)((uint32_t)p11type) != p11type) |
| { |
| printf("overflow attribute type\n"); |
| } |
| else |
| { |
| dumpCKA((unsigned long) p11type, 48); |
| printf("\n"); |
| } |
| |
| uint64_t disktype; |
| if (!readULong(stream, disktype)) |
| { |
| corrupt(stream); |
| return; |
| } |
| dumpULong(disktype); |
| switch (disktype) |
| { |
| case BOOLEAN_ATTR: |
| printf("boolean attribute\n"); |
| break; |
| case ULONG_ATTR: |
| printf("unsigned long attribute\n"); |
| break; |
| case BYTES_ATTR: |
| printf("byte string attribute\n"); |
| break; |
| case ATTRMAP_ATTR: |
| printf("attribute map attribute\n"); |
| break; |
| case MECHSET_ATTR: |
| printf("mechanism set attribute\n"); |
| break; |
| default: |
| printf("unknown attribute format\n"); |
| break; |
| } |
| |
| if (disktype == BOOLEAN_ATTR) |
| { |
| uint8_t value; |
| if (!readBool(stream, value)) |
| { |
| corrupt(stream); |
| return; |
| } |
| dumpBool(value); |
| printf("\n"); |
| } |
| else if (disktype == ULONG_ATTR) |
| { |
| uint64_t value; |
| if (!readULong(stream, value)) |
| { |
| corrupt(stream); |
| return; |
| } |
| dumpULong(value); |
| dumpCKx(p11type, value, 48); |
| printf("\n"); |
| } |
| else if (disktype == BYTES_ATTR) |
| { |
| uint64_t len; |
| if (!readULong(stream, len)) |
| { |
| corrupt(stream); |
| return; |
| } |
| dumpULong(len); |
| if (len > MAX_BYTES) |
| { |
| printf("overflow length...\n"); |
| return; |
| } |
| printf("(length %lu)\n", (unsigned long) len); |
| |
| std::vector<uint8_t> value((size_t) len); |
| if (!readBytes(stream, value)) |
| { |
| corrupt(stream); |
| return; |
| } |
| dumpBytes(value); |
| } |
| else if (disktype == ATTRMAP_ATTR) |
| { |
| uint64_t len; |
| if (!readULong(stream, len)) |
| { |
| corrupt(stream); |
| return; |
| } |
| dumpULong(len); |
| if (len > MAX_BYTES) |
| { |
| printf("overflow length...\n"); |
| return; |
| } |
| printf("(length %lu)\n", (unsigned long) len); |
| |
| std::vector<Attribute> value; |
| if (!readMap(stream, len, value)) |
| { |
| corrupt(stream); |
| return; |
| } |
| dumpMap(value); |
| } |
| else if (disktype == MECHSET_ATTR) |
| { |
| uint64_t len; |
| if (!readULong(stream, len)) |
| { |
| corrupt(stream); |
| return; |
| } |
| dumpULong(len); |
| if (len > MAX_BYTES) |
| { |
| printf("overflow length...\n"); |
| return; |
| } |
| printf("(length %lu)\n", (unsigned long) len); |
| |
| for (unsigned long i = 0; i < len; i++) |
| { |
| uint64_t mech; |
| if (!readULong(stream, mech)) |
| { |
| corrupt(stream); |
| return; |
| } |
| dumpULong(mech); |
| dumpCKM(mech, 48); |
| printf("\n"); |
| } |
| } |
| else |
| { |
| corrupt(stream); |
| return; |
| } |
| } |
| } |
| |
| // Display the usage |
| void usage() |
| { |
| printf("SoftHSM dump tool. From SoftHSM v2 object file.\n"); |
| printf("Usage: softhsm2-dump-file path\n"); |
| } |
| |
| // The main function |
| int main(int argc, char* argv[]) |
| { |
| FILE* stream; |
| |
| if (argc != 2) |
| { |
| usage(); |
| exit(0); |
| } |
| |
| stream = fopen(argv[1], "r"); |
| if (stream == NULL) |
| { |
| fprintf(stderr, "can't open object file %s\n", argv[1]); |
| exit(0); |
| } |
| |
| printf("Dump of object file \"%s\"\n", argv[1]); |
| dump(stream); |
| exit(1); |
| } |