diff --git a/sedutil-master/BUILDING b/sedutil-master/BUILDING new file mode 100644 index 0000000..94acdfb --- /dev/null +++ b/sedutil-master/BUILDING @@ -0,0 +1,11 @@ +sedutil is built using autotools and make. +steps: +autoreconf -i +./configure --enable-silent-rules +make +------------------------ +This will also build the PBA ignore it. + +If you get an errot building that says Version.h is missing +you need to make all. This is an issue with how autotools handles +built sources and dependencies. diff --git a/sedutil-master/CONTRIBUTING b/sedutil-master/CONTRIBUTING new file mode 100644 index 0000000..eb7722b --- /dev/null +++ b/sedutil-master/CONTRIBUTING @@ -0,0 +1,6 @@ +Contributing to the Drive Trust Alliance sedutil project. +We welcome contributions to the project but in order to maintain our ability to monitize this +software we require that contributions are accompanied by a signed copy of the +DTA_Contributor_Agreement_v2 included in this directory. + +Thanks for understanding \ No newline at end of file diff --git a/sedutil-master/Common/Copyright.txt b/sedutil-master/Common/Copyright.txt new file mode 100644 index 0000000..22c382a --- /dev/null +++ b/sedutil-master/Common/Copyright.txt @@ -0,0 +1,19 @@ +/* C:B************************************************************************** +This software is Copyright 2014-2017 Bright Plaza Inc. + +This file is part of sedutil. + +sedutil is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +sedutil is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with sedutil. If not, see . + + * C:E********************************************************************** */ diff --git a/sedutil-master/Common/DtaAnnotatedDump.cpp b/sedutil-master/Common/DtaAnnotatedDump.cpp new file mode 100644 index 0000000..c5eab78 --- /dev/null +++ b/sedutil-master/Common/DtaAnnotatedDump.cpp @@ -0,0 +1,402 @@ +/* C:B************************************************************************** +This software is Copyright 2014-2017 Bright Plaza Inc. + +This file is part of sedutil. + +sedutil is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +sedutil is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with sedutil. If not, see . + + * C:E********************************************************************** */ + + +#include "os.h" +#include +#include +#include +#include +#include "DtaDevEnterprise.h" +#include "DtaHashPwd.h" +#include "DtaEndianFixup.h" +#include "DtaStructures.h" +#include "DtaCommand.h" +#include "DtaResponse.h" +#include "DtaSession.h" +#include "DtaHexDump.h" +#include "DtaAnnotatedDump.h" + +using namespace std; + +//////////////////////////////////////////////////////////////////////////////// +DtaToken::DtaToken(void) : +//////////////////////////////////////////////////////////////////////////////// + m_TokenType (NONE), + m_HeaderLength (0), + m_DataLength (0), + m_TokenLength (0), + m_token (NULL), + m_data (NULL), + m_value (0ULL), + m_sign (false) +{ +} + +//////////////////////////////////////////////////////////////////////////////// +DtaToken::~DtaToken(void) +//////////////////////////////////////////////////////////////////////////////// +{ +} + +//////////////////////////////////////////////////////////////////////////////// +void DtaToken::str2int(uint8_t * buf, bool byte) +//////////////////////////////////////////////////////////////////////////////// +{ + // user says it's a byte string, or it's so large it must be + if (byte || m_DataLength > sizeof(m_value)) + { + m_data = buf; + m_value = 0ULL; + return; + } + + // zero-sized ? + if (m_DataLength == 0) + { + m_data = NULL; + m_value = 0ULL; + return; + } + + // zero-extend 1B to 8B sized BE integer + uint64_t V = 0; + uint8_t * n = (uint8_t *) &V; + + memset(n, '\0', sizeof(V)); + memcpy(n+(sizeof(V)-m_DataLength), buf, m_DataLength); + + // convert integer to host byte order + V = SWAP64(V); + + // sign-extend if appropriate + if (m_sign && (m_DataLength < sizeof(V))) + { + const int shift = 8 * (sizeof(V) - m_DataLength); + int64_t v = V; + v = v << shift; + v = v >> shift; + V = v; + } + + // write out integer value + m_data = NULL; + m_value = V; +} + +//////////////////////////////////////////////////////////////////////////////// +void DtaToken::parse(uint8_t * buf, uint32_t buflen) +//////////////////////////////////////////////////////////////////////////////// +{ + LOG(D1) << "Entering DtaToken::parse " << buflen; + m_token = buf; + + const CAtomHeader & atom = * (CAtomHeader *) buf; + + if (atom.TinyAtom.indicator == atom.TinyAtom.INDICATOR) + { + m_TokenType = TINY_ATOM; + m_sign = atom.TinyAtom.sign; + m_HeaderLength = atom.TinyAtom.HEADER_SIZE; + m_DataLength = 0; + m_TokenLength = atom.TinyAtom.HEADER_SIZE; + m_data = NULL; + if (m_sign) + { + m_value = int64_t(atom.TinyAtom_sign.value); + } + else + { + m_value = uint64_t(atom.TinyAtom.value); + } + } + else if (atom.ShortAtom.indicator == atom.ShortAtom.INDICATOR) + { + m_TokenType = SHORT_ATOM; + m_sign = atom.ShortAtom.sign; + m_HeaderLength = atom.ShortAtom.HEADER_SIZE; + m_DataLength = atom.ShortAtom.length; + m_TokenLength = atom.ShortAtom.HEADER_SIZE + m_DataLength; + str2int(m_token+atom.ShortAtom.HEADER_SIZE, atom.ShortAtom.byte); + } + else if (atom.MediumAtom.indicator == atom.MediumAtom.INDICATOR) + { + m_TokenType = MEDIUM_ATOM; + m_sign = atom.MediumAtom.sign; + m_HeaderLength = atom.MediumAtom.HEADER_SIZE; + m_DataLength = uint32_t(atom.MediumAtom.length_msb) << 8 | uint32_t(atom.MediumAtom.length_lsb); + m_TokenLength = atom.MediumAtom.HEADER_SIZE + m_DataLength; + str2int(m_token+atom.MediumAtom.HEADER_SIZE, atom.MediumAtom.byte); + } + else if (atom.LongAtom.indicator == atom.LongAtom.INDICATOR) + { + m_TokenType = LONG_ATOM; + m_sign = atom.LongAtom.sign; + m_HeaderLength = atom.LongAtom.HEADER_SIZE; + m_DataLength = (uint32_t(atom.LongAtom.length[0]) << 8 | uint32_t(atom.LongAtom.length[1])) << 8 | uint32_t(atom.LongAtom.length[2]); + m_TokenLength = atom.LongAtom.HEADER_SIZE + m_DataLength; + str2int(m_token+atom.LongAtom.HEADER_SIZE, atom.LongAtom.byte); + } + else + { + m_TokenType = TOKEN; + m_sign = 0; + m_HeaderLength = 1; + m_DataLength = 0; + m_TokenLength = 1; + m_data = NULL; + m_value = m_token[0]; + } +} + +//////////////////////////////////////////////////////////////////////////////// +int DtaToken::print(FILE *stream, uint32_t buflen) +//////////////////////////////////////////////////////////////////////////////// +{ + int ret = 0; + + ret += fprintf(stream, "%u\t", m_TokenLength); + + // print out atom header + unsigned int len = min(m_HeaderLength, buflen); + ret += fprintf(stream, "("); + for(unsigned int n=0; n 0) + { + buflen = 0; + ret += ret2; + } + } + for(unsigned int n=0; n>\n"); + else if (cmd == IF_SEND) + fprintf(stream, "<< IF_SEND >>\n"); + else + fprintf(stream, "<< 0x%2.2X\n >>\n", cmd); + + // echo header + OPALHeader h; + memcpy(&h, buffer, sizeof(h)); + IFLOG(D1) + { + fprintf(stream, "ComPacket.extendedComID %2.2X%2.2X%2.2X%2.2X\n", + h.cp.extendedComID[0], h.cp.extendedComID[1], h.cp.extendedComID[2], h.cp.extendedComID[3]); + fprintf(stream, "ComPacket.outstandingData %8.8X\n", SWAP32(h.cp.outstandingData)); + fprintf(stream, "ComPacket.minTransfer %8.8X\n", SWAP32(h.cp.minTransfer)); + fprintf(stream, "ComPacket.length %8.8X\n", SWAP32(h.cp.length)); + fprintf(stream, "Packet.TSN %8.8X\n", SWAP32(h.pkt.TSN)); + fprintf(stream, "Packet.HSN %8.8X\n", SWAP32(h.pkt.HSN)); + fprintf(stream, "Packet.seqNumber %8.8X\n", SWAP32(h.pkt.seqNumber)); + fprintf(stream, "Packet.ackType %8.8X\n", SWAP16(h.pkt.ackType)); + fprintf(stream, "Packet.acknowledgement %8.8X\n", SWAP32(h.pkt.acknowledgement)); + fprintf(stream, "Packet.length %8.8X\n", SWAP32(h.pkt.length)); + fprintf(stream, "DataSubPacket.kind %8.8X\n", SWAP16(h.subpkt.kind)); + fprintf(stream, "DataSubPacket.length %8.8X\n", SWAP32(h.subpkt.length)); + } + + const uint32_t buflen = SWAP32(h.subpkt.length); + if (buflen > bufferlen) + { + fprintf(stream, "Overflow: h.subpkt.length = %u, bufferlen = %u\n", buflen, bufferlen); + return 0xff; + } + + // set up pointers to scan buffer + unsigned char * p = (unsigned char *) buffer + sizeof(h); + unsigned char * q = p + buflen; + + // scan buffer + while(p < q) + { + DtaToken token; + token.parse(p, (uint32_t)(q-p)); + token.print(stream, (uint32_t)(q-p)); + + if (p + token.m_TokenLength > q) fprintf(stream, "(token truncated)"); + + p += token.m_TokenLength; + } + + return 0; +} diff --git a/sedutil-master/Common/DtaAnnotatedDump.h b/sedutil-master/Common/DtaAnnotatedDump.h new file mode 100644 index 0000000..734c8eb --- /dev/null +++ b/sedutil-master/Common/DtaAnnotatedDump.h @@ -0,0 +1,145 @@ +/* C:B************************************************************************** +This software is Copyright 2014-2017 Bright Plaza Inc. + +This file is part of sedutil. + +sedutil is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +sedutil is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with sedutil. If not, see . + + * C:E********************************************************************** */ + +#pragma pack(push,1) + +typedef union CAtomHeader_t +{ + // four bytes in big endian (network) byte order + uint8_t all[4]; + + // TINY ATOM + class CTinyAtom + { + public: + enum + { + INDICATOR = 0, // 0b + HEADER_SIZE = 1, + }; + unsigned value : 6; + unsigned sign : 1; + unsigned indicator : 1; + } TinyAtom; + + // TINY ATOM (sign) + class CTinyAtom_sign + { + public: + enum + { + INDICATOR = 0, // 0b + HEADER_SIZE = 1, + }; + signed value : 6; + unsigned sign : 1; + unsigned indicator : 1; + } TinyAtom_sign; + + // SHORT ATOM + class CShortAtom + { + public: + enum + { + INDICATOR = 2, // 10b + HEADER_SIZE = 1, + }; + unsigned length : 4; + unsigned sign : 1; + unsigned byte : 1; + unsigned indicator : 2; + } ShortAtom; + + // MEDIUM ATOM + class CMediumAtom + { + public: + enum + { + INDICATOR = 6, // 110b + HEADER_SIZE = 2, + }; + unsigned length_msb : 3; + unsigned sign : 1; + unsigned byte : 1; + unsigned indicator : 3; + uint8_t length_lsb; + } MediumAtom; + + // LONG ATOM + class CLongAtom + { + public: + enum + { + INDICATOR = 14, // 1110b + HEADER_SIZE = 4, + }; + unsigned sign : 1; + unsigned byte : 1; + unsigned reserved : 2; + unsigned indicator : 4; + uint8_t length[3]; + } LongAtom; + +} CAtomHeader; +#pragma pack(pop) +//////////////////////////////////////////////////////////////////////////////// +class DtaToken +//////////////////////////////////////////////////////////////////////////////// +{ +public: + DtaToken(void); + ~DtaToken(void); + + void parse(uint8_t * buf, uint32_t buflen); + + int print(FILE *stream, uint32_t buflen); + + typedef enum _TokenType + { + NONE, + TINY_ATOM, + SHORT_ATOM, + MEDIUM_ATOM, + LONG_ATOM, + TOKEN, + } TokenType; + + TokenType m_TokenType; + uint32_t m_HeaderLength; + uint32_t m_DataLength; + uint32_t m_TokenLength; + uint8_t * m_token; + uint8_t * m_data; + uint64_t m_value; + bool m_sign; + +private: + void str2int(uint8_t * buf, bool byte); + int printTokenType(FILE *stream, uint8_t token); + int printAscii(FILE *stream, uint8_t * buf, uint32_t buflen); + int printUID(FILE *stream, uint8_t buf[8]); +}; + +//////////////////////////////////////////////////////////////////////////////// +extern uint8_t DtaAnnotatedDump(ATACOMMAND cmd, void * buffer, uint32_t bufferlen); +//////////////////////////////////////////////////////////////////////////////// diff --git a/sedutil-master/Common/DtaCommand.cpp b/sedutil-master/Common/DtaCommand.cpp new file mode 100644 index 0000000..0148d34 --- /dev/null +++ b/sedutil-master/Common/DtaCommand.cpp @@ -0,0 +1,288 @@ +/* C:B************************************************************************** +This software is Copyright 2014-2017 Bright Plaza Inc. + +This file is part of sedutil. + +sedutil is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +sedutil is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with sedutil. If not, see . + + * C:E********************************************************************** */ +#include "os.h" +#include +#include "DtaCommand.h" +#include "DtaEndianFixup.h" +#include "DtaHexDump.h" +#include "DtaStructures.h" + +using namespace std; + +DtaCommand::DtaCommand() +{ + LOG(D1) << "Creating DtaCommand()"; + cmdbuf = commandbuffer + IO_BUFFER_ALIGNMENT; + cmdbuf = (uint8_t*)((uintptr_t)cmdbuf & (uintptr_t)~(IO_BUFFER_ALIGNMENT - 1)); + respbuf = responsebuffer + IO_BUFFER_ALIGNMENT; + respbuf = (uint8_t*)((uintptr_t)respbuf & (uintptr_t)~(IO_BUFFER_ALIGNMENT - 1)); +} + +/* Fill in the header information and format the call */ +DtaCommand::DtaCommand(OPAL_UID InvokingUid, OPAL_METHOD method) +{ + LOG(D1) << "Creating DtaCommand(ID, InvokingUid, method)"; + cmdbuf = commandbuffer + IO_BUFFER_ALIGNMENT; + cmdbuf = (uint8_t*)((uintptr_t)cmdbuf & (uintptr_t)~(IO_BUFFER_ALIGNMENT - 1)); + respbuf = responsebuffer + IO_BUFFER_ALIGNMENT; + respbuf = (uint8_t*)((uintptr_t)respbuf & (uintptr_t)~(IO_BUFFER_ALIGNMENT - 1)); + reset(InvokingUid, method); +} + +void +DtaCommand::reset() +{ + LOG(D1) << "Entering DtaCommand::reset()"; + memset(cmdbuf, 0, MAX_BUFFER_LENGTH); + memset(respbuf, 0, MIN_BUFFER_LENGTH); + bufferpos = sizeof (OPALHeader); +} +void +DtaCommand::reset(OPAL_UID InvokingUid, vector method){ + LOG(D1) << "Entering DtaCommand::reset(OPAL_UID,uint8_t)"; + reset(); + cmdbuf[bufferpos++] = OPAL_TOKEN::CALL; + addToken(InvokingUid); + addToken(method); +} +void +DtaCommand::reset(vector InvokingUid, vector method){ + LOG(D1) << "Entering DtaCommand::reset(uint8_t,uint8_t)"; + reset(); + cmdbuf[bufferpos++] = OPAL_TOKEN::CALL; + addToken(InvokingUid); + addToken(method); +} + +void +DtaCommand::reset(OPAL_UID InvokingUid, OPAL_METHOD method) +{ + LOG(D1) << "Entering DtaCommand::reset(OPAL_UID, OPAL_METHOD)"; + reset(); + cmdbuf[bufferpos++] = OPAL_TOKEN::CALL; + addToken(InvokingUid); + cmdbuf[bufferpos++] = OPAL_SHORT_ATOM::BYTESTRING8; + memcpy(&cmdbuf[bufferpos], &OPALMETHOD[method][0], 8); /* bytes 11-18 */ + bufferpos += 8; +} + +void +DtaCommand::addToken(uint64_t number) +{ + int startat = 0; + LOG(D1) << "Entering DtaCommand::addToken(uint64_t)"; + if (number < 64) { + cmdbuf[bufferpos++] = (uint8_t) number & 0x000000000000003f; + } + else { + if (number < 0x100) { + cmdbuf[bufferpos++] = 0x81; + startat = 0; + } + else if (number < 0x10000) { + cmdbuf[bufferpos++] = 0x82; + startat = 1; + } + else if (number < 0x100000000) { + cmdbuf[bufferpos++] = 0x84; + startat = 3; + } + else { + cmdbuf[bufferpos++] = 0x88; + startat = 7; + } + for (int i = startat; i > -1; i--) { + cmdbuf[bufferpos++] = (uint8_t) ((number >> (i * 8)) & 0x00000000000000ff); + } + } +} + +void +DtaCommand::addToken(vector token) +{ + LOG(D1) << "Entering addToken(vector)"; + for (uint32_t i = 0; i < token.size(); i++) { + cmdbuf[bufferpos++] = token[i]; + } +} + +void +DtaCommand::addToken(const char * bytestring) +{ + LOG(D1) << "Entering DtaCommand::addToken(const char * )"; + uint16_t length = (uint16_t) strlen(bytestring); + if (length == 0) { + /* null token e.g. default password */ + cmdbuf[bufferpos++] = (uint8_t)0xa1; + cmdbuf[bufferpos++] = (uint8_t)0x00; + } + else if (length < 16) { + /* use tiny atom */ + cmdbuf[bufferpos++] = (uint8_t) length | 0xa0; + } + else if (length < 2048) { + /* Use Medium Atom */ + cmdbuf[bufferpos++] = 0xd0 | (uint8_t) ((length >> 8) & 0x07); + cmdbuf[bufferpos++] = (uint8_t) (length & 0x00ff); + } + else { + /* Use Large Atom */ + LOG(E) << "FAIL -- can't send LARGE ATOM size bytestring in 2048 Packet"; + exit(EXIT_FAILURE); + } + memcpy(&cmdbuf[bufferpos], bytestring, length); + bufferpos += length; + +} + +void +DtaCommand::addToken(OPAL_TOKEN token) +{ + LOG(D1) << "Entering DtaCommand::addToken(OPAL_TOKEN)"; + cmdbuf[bufferpos++] = (uint8_t) token; +} + +void +DtaCommand::addToken(OPAL_SHORT_ATOM token) +{ + LOG(D1) << "Entering DtaCommand::addToken(OPAL_SHORT_ATOM)"; + cmdbuf[bufferpos++] = (uint8_t)token; +} + +void +DtaCommand::addToken(OPAL_TINY_ATOM token) +{ + LOG(D1) << "Entering DtaCommand::addToken(OPAL_TINY_ATOM)"; + cmdbuf[bufferpos++] = (uint8_t) token; +} + +void +DtaCommand::addToken(OPAL_UID token) +{ + LOG(D1) << "Entering DtaCommand::addToken(OPAL_UID)"; + cmdbuf[bufferpos++] = OPAL_SHORT_ATOM::BYTESTRING8; + memcpy(&cmdbuf[bufferpos], &OPALUID[token][0], 8); + bufferpos += 8; +} + +void +DtaCommand::complete(uint8_t EOD) +{ + LOG(D1) << "Entering DtaCommand::complete(uint8_t EOD)"; + if (EOD) { + cmdbuf[bufferpos++] = OPAL_TOKEN::ENDOFDATA; + cmdbuf[bufferpos++] = OPAL_TOKEN::STARTLIST; + cmdbuf[bufferpos++] = 0x00; + cmdbuf[bufferpos++] = 0x00; + cmdbuf[bufferpos++] = 0x00; + cmdbuf[bufferpos++] = OPAL_TOKEN::ENDLIST; + } + /* fill in the lengths and add the modulo 4 padding */ + OPALHeader * hdr; + hdr = (OPALHeader *) cmdbuf; + hdr->subpkt.length = SWAP32(bufferpos - (sizeof (OPALHeader))); + while (bufferpos % 4 != 0) { + cmdbuf[bufferpos++] = 0x00; + } + hdr->pkt.length = SWAP32((bufferpos - sizeof (OPALComPacket)) + - sizeof (OPALPacket)); + hdr->cp.length = SWAP32(bufferpos - sizeof (OPALComPacket)); + if (bufferpos > MAX_BUFFER_LENGTH) { + LOG(D1) << " Standard Buffer Overrun " << bufferpos; + exit(EXIT_FAILURE); + } +} + +void +DtaCommand::changeInvokingUid(std::vector Invoker) +{ + LOG(D1) << "Entering DtaCommand::changeInvokingUid()"; + int offset = sizeof (OPALHeader) + 1; /* bytes 2-9 */ + for (uint32_t i = 0; i < Invoker.size(); i++) { + cmdbuf[offset + i] = Invoker[i]; + } + +} + +void * +DtaCommand::getCmdBuffer() +{ + return cmdbuf; +} + +void * +DtaCommand::getRespBuffer() +{ + return respbuf; +} +void +DtaCommand::dumpCommand() +{ + OPALHeader * hdr = (OPALHeader *)cmdbuf; + DtaHexDump(cmdbuf, SWAP32(hdr->cp.length) + sizeof(OPALComPacket)); +} +void +DtaCommand::dumpResponse() +{ + OPALHeader *hdr = (OPALHeader *)respbuf; + DtaHexDump(respbuf, SWAP32(hdr->cp.length) + sizeof(OPALComPacket)); +} +uint16_t +DtaCommand::outputBufferSize() { +// if (MIN_BUFFER_LENGTH + 1 > bufferpos) return(MIN_BUFFER_LENGTH); + if(bufferpos % 512) + return(((uint16_t)(bufferpos / 512) + 1) * 512); + else + return((uint16_t)(bufferpos / 512) * 512); +} +void +DtaCommand::setcomID(uint16_t comID) +{ + OPALHeader * hdr; + hdr = (OPALHeader *) cmdbuf; + LOG(D1) << "Entering DtaCommand::setcomID()"; + hdr->cp.extendedComID[0] = ((comID & 0xff00) >> 8); + hdr->cp.extendedComID[1] = (comID & 0x00ff); + hdr->cp.extendedComID[2] = 0x00; + hdr->cp.extendedComID[3] = 0x00; +} + +void +DtaCommand::setTSN(uint32_t TSN) +{ + LOG(D1) << "Entering DtaCommand::setTSN()"; + OPALHeader * hdr; + hdr = (OPALHeader *) cmdbuf; + hdr->pkt.TSN = TSN; +} + +void +DtaCommand::setHSN(uint32_t HSN) +{ + LOG(D1) << "Entering DtaCommand::setHSN()"; + OPALHeader * hdr; + hdr = (OPALHeader *) cmdbuf; + hdr->pkt.HSN = HSN; +} + +DtaCommand::~DtaCommand() +{ + LOG(D1) << "Destroying DtaCommand"; +} diff --git a/sedutil-master/Common/DtaCommand.h b/sedutil-master/Common/DtaCommand.h new file mode 100644 index 0000000..35f7217 --- /dev/null +++ b/sedutil-master/Common/DtaCommand.h @@ -0,0 +1,133 @@ +/* C:B************************************************************************** +This software is Copyright 2014-2017 Bright Plaza Inc. + +This file is part of sedutil. + +sedutil is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +sedutil is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with sedutil. If not, see . + + * C:E********************************************************************** */ +#pragma once + +#include +#include "DtaLexicon.h" +class DtaDevOpal; +class DtaDevEnterprise; + +using namespace std; + +/** A class to build & send Opal Command streams to a TPer. +* This class attempts to closely mimic the command +* pseudo code used in the TCG documents, the syntactic +* sugar is not represented. See TCG document Storage Architecture +* Core Specification R2.00 V2.00 Section 3.2.1.2 for all +* the gory details. +* +* @see DtaLexicon.h for structs, typedefs and enums used to encode +* the bytestream. +*/ +class DtaCommand { + friend class DtaDevOpal; + friend class DtaDevEnterprise; +public: + /** Default constructor, allocates the command and resonse buffers. */ + DtaCommand(); + /** Constructor that initializes the incokingUid and method fields. + * @param InvokingUid The UID used to call the SSC method + * @param method The SSC method to be called + */ + DtaCommand(OPAL_UID InvokingUid, OPAL_METHOD method); + /** destructor frees the command and response buffers */ + ~DtaCommand(); + /** Add a Token to the bytstream of type OPAL_TOKEN. */ + void addToken(OPAL_TOKEN token); + /** Add a Token to the bytstream of type OPL_SHORT ATOM. */ + void addToken(OPAL_SHORT_ATOM token); + /** Add a Token to the bytstream of type OPL_TINY ATOM. */ + void addToken(OPAL_TINY_ATOM token); + /** Add a Token to the bytstream of from the OPALUID array. */ + void addToken(OPAL_UID token); + /** Add a Token to the bytstream of type c-string */ + void addToken(const char * bytestring); + /** Add a Token to the bytstream of type vector. + * This token must be a complete token properly encoded + * with the proper TCG bytestream header information */ + void addToken(std::vector token); + /** Add a Token to the bytstream of type uint64. */ + void addToken(uint64_t number); + /** Set the commid to be used in the command. */ + void setcomID(uint16_t comID); + /** set the Host session number to be used in the command. */ + void setHSN(uint32_t HSN); + /** Set the TPer session number to be used for the command. */ + void setTSN(uint32_t TSN); + /** Add the required fields to the end of the bytestream. If EOD is true (default) the + * EOD token and the method status list will be added to the end of the bytestream. + * Then the bytstram is padded to a 4-byte boundary if required and the length fields + * are populated in packet, subpacket and command packet. + * + * @param EOD a bool to signal that command requires the EOD and method status fields + */ + void complete(uint8_t EOD = 1); + /** Clears the command buffer and resets the the end of buffer pointer + * @see bufferpos + */ + void reset(); + /** Clears the command buffer and resets the the end of buffer pointer + * also initializes the invoker and method fields. + * + * @param InvokingUid The UID used to call the SSC method + * @param method The SSC method to be called + */ + void reset(OPAL_UID InvokingUid, OPAL_METHOD method); + /** Clears the command buffer and resets the the end of buffer pointer + * also initializes the invoker and method fields. + * The invoker is passed as a vector this is used for the case + * where the invoker is not an OPAL user, typically a table. + * + * @param InvokingUid The UID used to call the SSC method + * @param method The SSC method to be called + */ + void reset(OPAL_UID InvokingUid, vector method); + /** Clears the command buffer and resets the the end of buffer pointer + * also initializes the invoker and method fields. + * Both the invoker and method are passed as a vector + * + * @param InvokingUid The UID used to call the SSC method + * @param method The SSC method to be called + */ + void reset(vector InvokingUid, vector method); + /** Changes the invoker field. + * The invoker is passed as a vector this is used for the case + * where the invoker is not an OPAL user, typically a table. + * + * @param Invoker The UID used to call the SSC method + */ + void changeInvokingUid(vector Invoker); + /** Produce a hexdump of the response. Typically used in debugging and tracing */ + void dumpResponse(); + /** Produce a hexdump of the command. Typically used in debugging and tracing */ + void dumpCommand(); + /** Return the space used in the command buffer (rounded to 512 bytes) */ + uint16_t outputBufferSize(); +private: + /** return a pointer to the command buffer */ + void * getCmdBuffer(); + /** return a pointer to the response buffer. */ + void * getRespBuffer(); + uint8_t commandbuffer[MAX_BUFFER_LENGTH + IO_BUFFER_ALIGNMENT]; /**< buffer allocation allow for 1k alignment */ + uint8_t responsebuffer[MIN_BUFFER_LENGTH + IO_BUFFER_ALIGNMENT]; /**< buffer allocation allow for 1k alignment */ + uint8_t *cmdbuf; /**< Pointer to the command buffer */ + uint8_t *respbuf; /**< pointer to the response buffer */ + uint32_t bufferpos = 0; /**< position of the next byte in the command buffer */ +}; diff --git a/sedutil-master/Common/DtaConstants.h b/sedutil-master/Common/DtaConstants.h new file mode 100644 index 0000000..385f030 --- /dev/null +++ b/sedutil-master/Common/DtaConstants.h @@ -0,0 +1,50 @@ +/* C:B************************************************************************** +This software is Copyright 2014-2017 Bright Plaza Inc. + +This file is part of sedutil. + +sedutil is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +sedutil is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with sedutil. If not, see . + + * C:E********************************************************************** */ + /** MAX Length of input the IO buffers used */ +#define MAX_BUFFER_LENGTH 61440 +/** Length of input the IO buffers used */ +#define MIN_BUFFER_LENGTH 2048 +/** Alignment of the IO buffers. +* generic align on 1k boundary probably not needed +* but when things weren't working this was one of the +* things I tried to make it work. +*/ +#define IO_BUFFER_ALIGNMENT 1024 +/** maximum number of disks to be scanned */ +#define MAX_DISKS 20 +/** iomanip commands to hexdump a field */ +#define HEXON(x) "0x" << std::hex << std::setw(x) << std::setfill('0') +/** iomanip command to return to standard ascii output */ +#define HEXOFF std::dec << std::setw(0) << std::setfill(' ') +/** Return Codes */ +#define DTAERROR_UNSUPORTED_LOCKING_RANGE 0x81 +#define DTAERROR_OBJECT_CREATE_FAILED 0x82 +#define DTAERROR_INVALID_PARAMETER 0x83 +#define DTAERROR_OPEN_ERR 0x84 +#define DTAERROR_INVALID_LIFECYCLE 0x85 +#define DTAERROR_INVALID_COMMAND 0x86 +#define DTAERROR_AUTH_FAILED 0x87 +#define DTAERROR_COMMAND_ERROR 0x88 +#define DTAERROR_NO_METHOD_STATUS 0x89 +#define DTAERROR_NO_LOCKING_INFO 0x8a +/** Locking Range Configurations */ +#define DTA_DISABLELOCKING 0x00 +#define DTA_READLOCKINGENABLED 0x01 +#define DTA_WRITELOCKINGENABLED 0x02 diff --git a/sedutil-master/Common/DtaDev.cpp b/sedutil-master/Common/DtaDev.cpp new file mode 100644 index 0000000..0346acf --- /dev/null +++ b/sedutil-master/Common/DtaDev.cpp @@ -0,0 +1,302 @@ +/* C:B************************************************************************** +This software is Copyright 2014-2017 Bright Plaza Inc. + +This file is part of sedutil. + +sedutil is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +sedutil is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with sedutil. If not, see . + + * C:E********************************************************************** */ +/** Base device class. + * An OS port must create a subclass of this class + * implementing sendcmd, osmsSleep and identify + * specific to the IO requirements of that OS + */ +#include "os.h" +#include +#include +#include +#include "DtaOptions.h" +#include "DtaDev.h" +#include "DtaStructures.h" +#include "DtaConstants.h" +#include "DtaEndianFixup.h" +#include "DtaHexDump.h" + +using namespace std; + +/** Device Class (Base) represents a single disk device. + * This is the functionality that is common to all OS's and SSC's + */ +DtaDev::DtaDev() +{ +} +DtaDev::~DtaDev() +{ +} +uint8_t DtaDev::isOpal2() +{ + LOG(D1) << "Entering DtaDev::isOpal2 " << (uint16_t) disk_info.OPAL20; + return disk_info.OPAL20; +} +uint8_t DtaDev::isOpal1() +{ + LOG(D1) << "Entering DtaDev::isOpal1() " << (uint16_t)disk_info.OPAL10; + return disk_info.OPAL10; +} +uint8_t DtaDev::isEprise() +{ + LOG(D1) << "Entering DtaDev::isEprise " << (uint16_t) disk_info.Enterprise; + return disk_info.Enterprise; +} + +uint8_t DtaDev::isAnySSC() +{ + LOG(D1) << "Entering DtaDev::isAnySSC " << (uint16_t)disk_info.ANY_OPAL_SSC; + return disk_info.ANY_OPAL_SSC; +} +uint8_t DtaDev::isPresent() +{ + LOG(D1) << "Entering DtaDev::isPresent() " << (uint16_t) isOpen; + return isOpen; +} +uint8_t DtaDev::MBREnabled() +{ + LOG(D1) << "Entering DtaDev::MBRENabled" << (uint16_t)disk_info.Locking_MBREnabled; + return disk_info.Locking_MBREnabled; +} +uint8_t DtaDev::MBRDone() +{ + LOG(D1) << "Entering DtaDev::MBRDone" << (uint16_t)disk_info.Locking_MBRDone; + return disk_info.Locking_MBRDone; +} +uint8_t DtaDev::Locked() +{ + LOG(D1) << "Entering DtaDev::Locked" << (uint16_t)disk_info.Locking_locked; + return disk_info.Locking_locked; +} +uint8_t DtaDev::LockingEnabled() +{ + LOG(D1) << "Entering DtaDev::LockingEnabled" << (uint16_t)disk_info.Locking_lockingEnabled; + return disk_info.Locking_lockingEnabled; +} +char *DtaDev::getFirmwareRev() +{ + return (char *)&disk_info.firmwareRev; +} +char *DtaDev::getModelNum() +{ + return (char *)&disk_info.modelNum; +} +char *DtaDev::getSerialNum() +{ + return (char *)&disk_info.serialNum; +} +DTA_DEVICE_TYPE DtaDev::getDevType() + { + return disk_info.devType; + } +void DtaDev::discovery0() +{ + LOG(D1) << "Entering DtaDev::discovery0()"; + uint8_t lastRC; + void * d0Response = NULL; + uint8_t * epos, *cpos; + Discovery0Header * hdr; + Discovery0Features * body; + d0Response = discovery0buffer + IO_BUFFER_ALIGNMENT; + d0Response = (void *)((uintptr_t)d0Response & (uintptr_t)~(IO_BUFFER_ALIGNMENT - 1)); + memset(d0Response, 0, MIN_BUFFER_LENGTH); + if ((lastRC = sendCmd(IF_RECV, 0x01, 0x0001, d0Response, MIN_BUFFER_LENGTH)) != 0) { + LOG(D) << "Send D0 request to device failed " << (uint16_t)lastRC; + return; + } + + epos = cpos = (uint8_t *) d0Response; + hdr = (Discovery0Header *) d0Response; + LOG(D3) << "Dumping D0Response"; + IFLOG(D3) DtaHexDump(hdr, SWAP32(hdr->length)); + epos = epos + SWAP32(hdr->length); + cpos = cpos + 48; // TODO: check header version + + do { + body = (Discovery0Features *) cpos; + switch (SWAP16(body->TPer.featureCode)) { /* could use of the structures here is a common field */ + case FC_TPER: /* TPer */ + disk_info.TPer = 1; + disk_info.TPer_ACKNACK = body->TPer.acknack; + disk_info.TPer_async = body->TPer.async; + disk_info.TPer_bufferMgt = body->TPer.bufferManagement; + disk_info.TPer_comIDMgt = body->TPer.comIDManagement; + disk_info.TPer_streaming = body->TPer.streaming; + disk_info.TPer_sync = body->TPer.sync; + break; + case FC_LOCKING: /* Locking*/ + disk_info.Locking = 1; + disk_info.Locking_locked = body->locking.locked; + disk_info.Locking_lockingEnabled = body->locking.lockingEnabled; + disk_info.Locking_lockingSupported = body->locking.lockingSupported; + disk_info.Locking_MBRDone = body->locking.MBRDone; + disk_info.Locking_MBREnabled = body->locking.MBREnabled; + disk_info.Locking_mediaEncrypt = body->locking.mediaEncryption; + break; + case FC_GEOMETRY: /* Geometry Features */ + disk_info.Geometry = 1; + disk_info.Geometry_align = body->geometry.align; + disk_info.Geometry_alignmentGranularity = SWAP64(body->geometry.alignmentGranularity); + disk_info.Geometry_logicalBlockSize = SWAP32(body->geometry.logicalBlockSize); + disk_info.Geometry_lowestAlignedLBA = SWAP64(body->geometry.lowestAlighedLBA); + break; + case FC_ENTERPRISE: /* Enterprise SSC */ + disk_info.Enterprise = 1; + disk_info.ANY_OPAL_SSC = 1; + disk_info.Enterprise_rangeCrossing = body->enterpriseSSC.rangeCrossing; + disk_info.Enterprise_basecomID = SWAP16(body->enterpriseSSC.baseComID); + disk_info.Enterprise_numcomID = SWAP16(body->enterpriseSSC.numberComIDs); + break; + case FC_OPALV100: /* Opal V1 */ + disk_info.OPAL10 = 1; + disk_info.ANY_OPAL_SSC = 1; + disk_info.OPAL10_basecomID = SWAP16(body->opalv100.baseComID); + disk_info.OPAL10_numcomIDs = SWAP16(body->opalv100.numberComIDs); + break; + case FC_SINGLEUSER: /* Single User Mode */ + disk_info.SingleUser = 1; + disk_info.SingleUser_all = body->singleUserMode.all; + disk_info.SingleUser_any = body->singleUserMode.any; + disk_info.SingleUser_policy = body->singleUserMode.policy; + disk_info.SingleUser_lockingObjects = SWAP32(body->singleUserMode.numberLockingObjects); + break; + case FC_DATASTORE: /* Datastore Tables */ + disk_info.DataStore = 1; + disk_info.DataStore_maxTables = SWAP16(body->datastore.maxTables); + disk_info.DataStore_maxTableSize = SWAP32(body->datastore.maxSizeTables); + disk_info.DataStore_alignment = SWAP32(body->datastore.tableSizeAlignment); + break; + case FC_OPALV200: /* OPAL V200 */ + disk_info.OPAL20 = 1; + disk_info.ANY_OPAL_SSC = 1; + disk_info.OPAL20_basecomID = SWAP16(body->opalv200.baseCommID); + disk_info.OPAL20_initialPIN = body->opalv200.initialPIN; + disk_info.OPAL20_revertedPIN = body->opalv200.revertedPIN; + disk_info.OPAL20_numcomIDs = SWAP16(body->opalv200.numCommIDs); + disk_info.OPAL20_numAdmins = SWAP16(body->opalv200.numlockingAdminAuth); + disk_info.OPAL20_numUsers = SWAP16(body->opalv200.numlockingUserAuth); + disk_info.OPAL20_rangeCrossing = body->opalv200.rangeCrossing; + break; + default: + if (0xbfff < (SWAP16(body->TPer.featureCode))) { + // silently ignore vendor specific segments as there is no public doc on them + disk_info.VendorSpecific += 1; + } + else { + disk_info.Unknown += 1; + LOG(D) << "Unknown Feature in Discovery 0 response " << std::hex << SWAP16(body->TPer.featureCode) << std::dec; + /* should do something here */ + } + break; + } + cpos = cpos + (body->TPer.length + 4); + } + while (cpos < epos); + +} +void DtaDev::puke() +{ + LOG(D1) << "Entering DtaDev::puke()"; + /* IDENTIFY */ + cout << endl << dev << (disk_info.devType == DEVICE_TYPE_ATA ? " ATA " : + disk_info.devType == DEVICE_TYPE_SAS ? " SAS " : + disk_info.devType == DEVICE_TYPE_USB ? " USB " : + disk_info.devType == DEVICE_TYPE_NVME ? " NVMe " : + " OTHER "); + cout << disk_info.modelNum << " " << disk_info.firmwareRev << " " << disk_info.serialNum << endl; + /* TPer */ + if (disk_info.TPer) { + cout << "TPer function (" << HEXON(4) << FC_TPER << HEXOFF << ")" << std::endl; + cout << " ACKNAK = " << (disk_info.TPer_ACKNACK ? "Y, " : "N, ") + << "ASYNC = " << (disk_info.TPer_async ? "Y, " : "N. ") + << "BufferManagement = " << (disk_info.TPer_bufferMgt ? "Y, " : "N, ") + << "comIDManagement = " << (disk_info.TPer_comIDMgt ? "Y, " : "N, ") + << "Streaming = " << (disk_info.TPer_streaming ? "Y, " : "N, ") + << "SYNC = " << (disk_info.TPer_sync ? "Y" : "N") + << std::endl; + } + if (disk_info.Locking) { + + cout << "Locking function (" << HEXON(4) << FC_LOCKING << HEXOFF << ")" << std::endl; + cout << " Locked = " << (disk_info.Locking_locked ? "Y, " : "N, ") + << "LockingEnabled = " << (disk_info.Locking_lockingEnabled ? "Y, " : "N, ") + << "LockingSupported = " << (disk_info.Locking_lockingSupported ? "Y, " : "N, "); + cout << "MBRDone = " << (disk_info.Locking_MBRDone ? "Y, " : "N, ") + << "MBREnabled = " << (disk_info.Locking_MBREnabled ? "Y, " : "N, ") + << "MediaEncrypt = " << (disk_info.Locking_mediaEncrypt ? "Y" : "N") + << std::endl; + } + if (disk_info.Geometry) { + + cout << "Geometry function (" << HEXON(4) << FC_GEOMETRY << HEXOFF << ")" << std::endl; + cout << " Align = " << (disk_info.Geometry_align ? "Y, " : "N, ") + << "Alignment Granularity = " << disk_info.Geometry_alignmentGranularity + << " (" << // display bytes + (disk_info.Geometry_alignmentGranularity * + disk_info.Geometry_logicalBlockSize) + << ")" + << ", Logical Block size = " << disk_info.Geometry_logicalBlockSize + << ", Lowest Aligned LBA = " << disk_info.Geometry_lowestAlignedLBA + << std::endl; + } + if (disk_info.Enterprise) { + cout << "Enterprise function (" << HEXON(4) << FC_ENTERPRISE << HEXOFF << ")" << std::endl; + cout << " Range crossing = " << (disk_info.Enterprise_rangeCrossing ? "Y, " : "N, ") + << "Base comID = " << HEXON(4) << disk_info.Enterprise_basecomID + << ", comIDs = " << disk_info.Enterprise_numcomID << HEXOFF + << std::endl; + } + if (disk_info.OPAL10) { + cout << "Opal V1.0 function (" << HEXON(4) << FC_OPALV100 << HEXOFF << ")" << std::endl; + cout << "Base comID = " << HEXON(4) << disk_info.OPAL10_basecomID << HEXOFF + << ", comIDs = " << disk_info.OPAL10_numcomIDs + << std::endl; + } + if (disk_info.SingleUser) { + cout << "SingleUser function (" << HEXON(4) << FC_SINGLEUSER << HEXOFF << ")" << std::endl; + cout << " ALL = " << (disk_info.SingleUser_all ? "Y, " : "N, ") + << "ANY = " << (disk_info.SingleUser_any ? "Y, " : "N, ") + << "Policy = " << (disk_info.SingleUser_policy ? "Y, " : "N, ") + << "Locking Objects = " << (disk_info.SingleUser_lockingObjects) + << std::endl; + } + if (disk_info.DataStore) { + cout << "DataStore function (" << HEXON(4) << FC_DATASTORE << HEXOFF << ")" << std::endl; + cout << " Max Tables = " << disk_info.DataStore_maxTables + << ", Max Size Tables = " << disk_info.DataStore_maxTableSize + << ", Table size alignment = " << disk_info.DataStore_alignment + << std::endl; + } + + if (disk_info.OPAL20) { + cout << "OPAL 2.0 function (" << HEXON(4) << FC_OPALV200 << ")" << HEXOFF << std::endl; + cout << " Base comID = " << HEXON(4) << disk_info.OPAL20_basecomID << HEXOFF; + cout << ", Initial PIN = " << HEXON(2) << static_cast(disk_info.OPAL20_initialPIN) << HEXOFF; + cout << ", Reverted PIN = " << HEXON(2) << static_cast(disk_info.OPAL20_revertedPIN) << HEXOFF; + cout << ", comIDs = " << disk_info.OPAL20_numcomIDs; + cout << std::endl; + cout << " Locking Admins = " << disk_info.OPAL20_numAdmins; + cout << ", Locking Users = " << disk_info.OPAL20_numUsers; + cout << ", Range Crossing = " << (disk_info.OPAL20_rangeCrossing ? "Y" : "N"); + cout << std::endl; + } + if (disk_info.Unknown) + cout << "**** " << (uint16_t)disk_info.Unknown << " **** Unknown function codes IGNORED " << std::endl; +} diff --git a/sedutil-master/Common/DtaDev.h b/sedutil-master/Common/DtaDev.h new file mode 100644 index 0000000..33655a1 --- /dev/null +++ b/sedutil-master/Common/DtaDev.h @@ -0,0 +1,303 @@ +/* C:B************************************************************************** +This software is Copyright 2014-2017 Bright Plaza Inc. + +This file is part of sedutil. + +sedutil is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +sedutil is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with sedutil. If not, see . + + * C:E********************************************************************** */ +#pragma once +#include "DtaStructures.h" +#include "DtaLexicon.h" +#include +#include "DtaOptions.h" +#include "DtaResponse.h" +class DtaCommand; +class DtaSession; + +using namespace std; +/** Base class for a disk device. + * This is a virtual base class defining the minimum functionality of device + * object. The methods defined here are called by other parts of the program + * so must be present in all devices + */ +class DtaDev { +public: + /** Default constructor, does nothing */ + DtaDev(); + /** Default destructor, does nothing*/ + virtual ~DtaDev(); + /** Does the device conform to the OPAL 2.0 SSC */ + uint8_t isOpal2(); + /** Does the device conform to the OPAL 1.0 SSC */ + uint8_t isOpal1(); + /** Does the device conform to the OPAL Enterprise SSC */ + uint8_t isEprise(); + /** Does the device conform to ANY TCG storage SSC */ + uint8_t isAnySSC(); + /** Is the MBREnabled flag set */ + uint8_t MBREnabled(); + /** Is the MBRDone flag set */ + uint8_t MBRDone(); + /** Is the Locked flag set */ + uint8_t Locked(); + /** Is the Locking SP enabled */ + uint8_t LockingEnabled(); + /** Is there an OS disk represented by this object */ + uint8_t isPresent(); + /** Returns the Firmware revision reported by the identify command */ + char *getFirmwareRev(); + /** Returns the Model Number reported by the Identify command */ + char *getModelNum(); + /** Returns the Serial Number reported by the Identify command */ + char *getSerialNum(); + /* What type of disk attachment is used */ + DTA_DEVICE_TYPE getDevType(); + /** displays the information returned by the Discovery 0 reply */ + virtual void puke(); + + /** Decode the Discovery 0 response. Scans the D0 response and creates a structure + * that can be queried later as required.This code also takes care of + * the endianess conversions either via a bitswap in the structure or executing + * a macro when the input buffer is read. + */ + void discovery0(); + + /* + * virtual methods required in the OS specific + * device class + */ + /** OS specific initialization. + * This function should perform the necessary authority and environment checking + * to allow proper functioning of the program, open the device, perform an ATA + * identify, add the fields from the identify response to the disk info structure + * and if the device is an ATA device perform a call to Discovery0() to complete + * the disk_info structure + * @param devref character representation of the device is standard OS lexicon + */ + virtual void init(const char * devref) = 0; + /** OS specific method to send an ATA command to the device + * @param cmd ATA command to be sent to the device + * @param protocol security protocol to be used in the command + * @param comID communications ID to be used + * @param buffer input/output buffer + * @param bufferlen length of the input/output buffer + */ + virtual uint8_t sendCmd(ATACOMMAND cmd, uint8_t protocol, uint16_t comID, + void * buffer, uint32_t bufferlen) = 0; + /** OS specific command to Wait for specified number of milliseconds + * @param milliseconds number of milliseconds to wait + */ + virtual void osmsSleep(uint32_t milliseconds) = 0; + /** OS specific routine to send an ATA identify to the device */ + virtual void identify(OPAL_DiskInfo& disk_info) = 0; + /** OS specific routine to get size of the device */ + virtual unsigned long long getSize() = 0; + /* + * virtual functions required to be implemented + * because they are called by sedutil.cpp + */ + /** User command to prepare the device for management by sedutil. + * Specific to the SSC that the device supports + * @param password the password that is to be assigned to the SSC master entities + */ + virtual uint8_t initialSetup(char * password) = 0; + /** User command to prepare the drive for Single User Mode and rekey a SUM locking range. + * @param lockingrange locking range number to enable + * @param start LBA to start locking range + * @param length length (in blocks) for locking range + * @param Admin1Password admin1 password for TPer + * @param password User password to set for locking range + */ + virtual uint8_t setup_SUM(uint8_t lockingrange, uint64_t start, uint64_t length, char *Admin1Password, char * password) = 0; + /** Set the SID password. + * Requires special handling because password is not always hashed. + * @param oldpassword current SID password + * @param newpassword value password is to be changed to + * @param hasholdpwd is the old password to be hashed before being added to the bytestream + * @param hashnewpwd is the new password to be hashed before being added to the bytestream + */ + virtual uint8_t setSIDPassword(char * oldpassword, char * newpassword, + uint8_t hasholdpwd = 1, uint8_t hashnewpwd = 1) = 0; + /** Set the password of a locking SP user. + * @param password current password + * @param userid the userid whose password is to be changed + * @param newpassword value password is to be changed to + */ + virtual uint8_t setPassword(char * password, char * userid, char * newpassword) = 0; + /** Set the password of a locking SP user in Single User Mode. + * @param password current user password + * @param userid the userid whose password is to be changed + * @param newpassword value password is to be changed to + */ + virtual uint8_t setNewPassword_SUM(char * password, char * userid, char * newpassword) = 0; + /** Loads a disk image file to the shadow MBR table. + * @param password the password for the administrative authority with access to the table + * @param filename the filename of the disk image + */ + virtual uint8_t loadPBA(char * password, char * filename) = 0; + /** Change the locking state of a locking range + * @param lockingrange The number of the locking range (0 = global) + * @param lockingstate the locking state to set + * @param Admin1Password password of administrative authority for locking range + */ + virtual uint8_t setLockingRange(uint8_t lockingrange, uint8_t lockingstate, + char * Admin1Password) = 0; + /** Change the locking state of a locking range in Single User Mode + * @param lockingrange The number of the locking range (0 = global) + * @param lockingstate the locking state to set + * @param password password of user authority for the locking range + */ + virtual uint8_t setLockingRange_SUM(uint8_t lockingrange, uint8_t lockingstate, + char * password) = 0; + /** Change the active state of a locking range + * @param lockingrange The number of the locking range (0 = global) + * @param enabled enable (true) or disable (false) the lockingrange + * @param password Password of administrative authority for locking range + */ + virtual uint8_t configureLockingRange(uint8_t lockingrange, uint8_t enabled, + char * password) = 0; + /** Setup a locking range. Initialize a locking range, set it's start + * LBA and length, initialize it as unlocked with locking disabled. + * @paran lockingrange The Locking Range to be setup + * @param start Starting LBA + * @param length Number of blocks + * @param password Password of administrator + */ + virtual uint8_t setupLockingRange(uint8_t lockingrange, uint64_t start, + uint64_t length, char * password) = 0; + /** Setup a locking range in Single User Mode. Initialize a locking range, + * set it's start LBA and length, initialize it as unlocked with locking enabled. + * @paran lockingrange The Locking Range to be setup + * @param start Starting LBA + * @param length Number of blocks + * @param password Password of administrator + */ + virtual uint8_t setupLockingRange_SUM(uint8_t lockingrange, uint64_t start, + uint64_t length, char * password) = 0; + /** List status of locking ranges. + * @param password Password of administrator + */ + virtual uint8_t listLockingRanges(char * password, int16_t rangeid) = 0; + /** Generate a new encryption key for a locking range. + * @param lockingrange locking range number + * @param password password of the locking administrative authority + */ + virtual uint8_t rekeyLockingRange(uint8_t lockingrange, char * password) = 0; + /** Enable bands using MSID. + * @param lockingrange locking range number + */ + virtual uint8_t setBandsEnabled(int16_t rangeid, char * password) = 0; + /** Primitive to set the MBRDone flag. + * @param state 0 or 1 + * @param Admin1Password Locking SP authority with access to flag + */ + virtual uint8_t setMBRDone(uint8_t state, char * Admin1Password) = 0; + /** Primitive to set the MBREnable flag. + * @param state 0 or 1 + * @param Admin1Password Locking SP authority with access to flag + */ + virtual uint8_t setMBREnable(uint8_t state, char * Admin1Password) = 0; + /** enable a locking sp user. + * @param password password of locking sp administrative authority + * @param userid the user to be enabled + */ + virtual uint8_t enableUser(char * password, char * userid, OPAL_TOKEN status = OPAL_TOKEN::OPAL_TRUE) = 0; + /** Enable locking on the device + * @param password password of the admin sp SID authority + */ + virtual uint8_t activateLockingSP(char * password) = 0; + /** Enable locking on the device in Single User Mode + * @param lockingrange the locking range number to activate in SUM + * @param password password of the admin sp SID authority + */ + virtual uint8_t activateLockingSP_SUM(uint8_t lockingrange, char * password) = 0; + /** Erase a Single User Mode locking range by calling the drive's erase method + * @param lockingrange The Locking Range to erase + * @param password The administrator password for the drive + */ + virtual uint8_t eraseLockingRange_SUM(uint8_t lockingrange, char * password) = 0; + /** Change the SID password from it's MSID default + * @param newpassword new password for SID and locking SP admins + */ + virtual uint8_t takeOwnership(char * newpassword) = 0; + /** Reset the Locking SP to its factory default condition + * ERASES ALL DATA! + * @param password of Administrative user + * @param keep true false for noerase function NOT WWORKING + */ + virtual uint8_t revertLockingSP(char * password, uint8_t keep = 0) = 0; + /** Reset the TPER to its factory condition + * ERASES ALL DATA! + * @param password password of authority (SID or PSID) + * @param PSID true or false is the authority the PSID + * */ + virtual uint8_t revertTPer(char * password, uint8_t PSID = 0, uint8_t AdminSP = 0 ) = 0; + /** Erase a locking range + * @param lockingrange The number of the locking range (0 = global) + * @param password Password of administrative authority for locking range + */ + virtual uint8_t eraseLockingRange(uint8_t lockingrange, char * password) = 0; + /** Dumps an object for diagnostic purposes + * @param sp index into the OPALUID table for the SP the object is in + * @param auth the authority ti use for the dump + * @param pass the password for the suthority + * @param objID the UID of the object to dump + * */ + virtual uint8_t objDump(char *sp, char * auth, char *pass, + char * objID) = 0; + /** Issue any command to the drive for diagnostic purposes + * @param sp index into the OPALUID table for the SP the object is in + * @param auth the authority ti use for the dump + * @param pass the password for the suthority + * @param invoker caller of the method + * @param method the method to call + * @param plist the parameter list for the command + * + */ + virtual uint8_t rawCmd(char *sp, char * auth, char *pass, + char *invoker, char *method, char *plist) = 0; + /** Read MSID + */ + virtual uint8_t printDefaultPassword() = 0; + + + virtual uint8_t readDataStore(char* filename, char* pass) = 0; + + virtual uint8_t writeDataStore(char* filename, char* pass) = 0; + /* + * virtual functions required to be implemented + * because they are called by DtaSession.cpp + */ + /** Send a command to the device and wait for the response + * @param cmd the MswdCommand object containing the command + * @param response the DtaResonse object containing the response + * @param protocol The security protocol number to use for the command + */ + virtual uint8_t exec(DtaCommand * cmd, DtaResponse & resp, uint8_t protocol = 0x01) = 0; + /** return the communications ID to be used for sessions to this device */ + virtual uint16_t comID() = 0; + bool no_hash_passwords; /** disables hashing of passwords */ + sedutiloutput output_format; /** standard, readable, JSON */ +protected: + const char * dev; /**< character string representing the device in the OS lexicon */ + uint8_t isOpen = FALSE; /**< The device has been opened */ + OPAL_DiskInfo disk_info; /**< Structure containing info from identify and discovery 0 */ + DtaResponse response; /**< shared response object */ + DtaResponse propertiesResponse; /**< response fron properties exchange */ + DtaSession *session; /**< shared session object pointer */ + uint8_t discovery0buffer[MIN_BUFFER_LENGTH + IO_BUFFER_ALIGNMENT]; + uint32_t tperMaxPacket = 2048; + uint32_t tperMaxToken = 1950; +}; diff --git a/sedutil-master/Common/DtaDevEnterprise.cpp b/sedutil-master/Common/DtaDevEnterprise.cpp new file mode 100644 index 0000000..cb9a1ef --- /dev/null +++ b/sedutil-master/Common/DtaDevEnterprise.cpp @@ -0,0 +1,1692 @@ +/* C:B************************************************************************** +This software is Copyright 2014-2017 Bright Plaza Inc. +This software is Copyright 2017 Spectra Logic Corporation + +This file is part of sedutil. + +sedutil is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +sedutil is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with sedutil. If not, see . + + * C:E********************************************************************** */ +#include "os.h" +#include +#include +#include +#include +#include "DtaDevEnterprise.h" +#include "DtaHashPwd.h" +#include "DtaEndianFixup.h" +#include "DtaStructures.h" +#include "DtaCommand.h" +#include "DtaResponse.h" +#include "DtaSession.h" +#include "DtaHexDump.h" +#include "DtaAnnotatedDump.h" +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4100) +#endif +using namespace std; + + +//////////////////////////////////////////////////////////////////////////////// +static const bool is_NULL_UID(std::vector & v) +//////////////////////////////////////////////////////////////////////////////// +{ + return + v.size() == 9 + && v[0] == 0xa8 + && v[1] == 0x00 + && v[2] == 0x00 + && v[3] == 0x00 + && v[4] == 0x00 + && v[5] == 0x00 + && v[6] == 0x00 + && v[7] == 0x00 + && v[8] == 0x00 + ; +} + +//////////////////////////////////////////////////////////////////////////////// +static void set8(vector & v, const uint8_t value[8]) +//////////////////////////////////////////////////////////////////////////////// +{ + v.clear(); + v.push_back(OPAL_SHORT_ATOM::BYTESTRING8); + for (int i = 0; i < 8; i++) + { + v.push_back(value[i]); + } +} + +//////////////////////////////////////////////////////////////////////////////// +static void setband(vector & v, uint16_t i) +//////////////////////////////////////////////////////////////////////////////// +{ + const uint16_t j = i+1; + v[1+6] = (uint8_t(j >> 8) | v[1+6]) & 0xF0; + v[1+7] = uint8_t(j); +} + +//////////////////////////////////////////////////////////////////////////////// +static void user2cpin(vector & dst, vector & src) +//////////////////////////////////////////////////////////////////////////////// +{ + // this works for BandMasterN and EraseMaster + // Table 29 Locking C_PIN table, p. 72 of Enterprise SSC rev 3.00 + dst = src; + dst[1+3] = 0x0B; +} + +//////////////////////////////////////////////////////////////////////////////// +uint8_t DtaDevEnterprise::getMaxRanges(char * password, uint16_t *maxRanges) +//////////////////////////////////////////////////////////////////////////////// +{ + uint8_t lastRC; + + // 5.7.2.1.5 MaxRanges + // This value defines the maximum number of supportable LBA ranges in addition + // to the Global Range. If this value is 0, then the only range available is + // the entire Global Range of the Storage Device. + // + // Therefore: 0 <= supported range <= MaxRanges + + // create session + session = new DtaSession(this); + if (session == NULL) { + LOG(E) << "Unable to create session object "; + return DTAERROR_OBJECT_CREATE_FAILED; + } + if ((lastRC = session->start(OPAL_UID::ENTERPRISE_LOCKINGSP_UID)) != 0) { + delete session; + return lastRC; + } + + //** Table 36 "LockingInfo table", p. 72 of Enterprise SSC rev 3.00 + vector table; + set8(table, OPALUID[ENTERPRISE_LOCKING_INFO_TABLE]); + + // query row 1 of LockingInfo table + if ((lastRC = getTable(table, "MaxRanges", "MaxRanges")) != 0) { + delete session; + return getMaxRangesOpal(password, maxRanges); + } + delete session; + + // "MaxRanges" is token 5 of response + *maxRanges = response.getUint16(5); + return 0; +} + +//////////////////////////////////////////////////////////////////////////////// +uint8_t DtaDevEnterprise::getMaxRangesOpal(char * password, uint16_t *maxRanges) +//////////////////////////////////////////////////////////////////////////////// +{ + uint8_t lastRC; + + // create session + session = new DtaSession(this); + if (session == NULL) { + LOG(E) << "Unable to create session object "; + return DTAERROR_OBJECT_CREATE_FAILED; + } + if ((lastRC = session->start(OPAL_UID::ENTERPRISE_LOCKINGSP_UID)) != 0) { + delete session; + return lastRC; + } + + //** Table 36 "LockingInfo table", p. 72 of Enterprise SSC rev 3.00 + vector table; + set8(table, OPALUID[OPAL_LOCKING_INFO_TABLE]); + + // query row 1 of LockingInfo table + if ((lastRC = getTable(table, "MaxRanges", "MaxRanges")) != 0) { + LOG(E) << "Unable to get MaxRanges from LockingInfo table"; + delete session; + return lastRC; + } + delete session; + + // "MaxRanges" is token 5 of response + *maxRanges = response.getUint16(5); + return 0; +} + +DtaDevEnterprise::DtaDevEnterprise(const char * devref) +{ + DtaDevOS::init(devref); + assert(isEprise()); + if (properties()) { LOG(E) << "Properties exchange failed"; } +} +DtaDevEnterprise::~DtaDevEnterprise() +{ +} +uint8_t DtaDevEnterprise::initialSetup(char * password) +{ + LOG(D1) << "Entering initialSetup()"; + uint8_t lastRC; + + if ((lastRC = takeOwnership(password)) != 0) { + LOG(E) << "Initial setup failed - unable to take ownership"; + return lastRC; + } + if ((lastRC = setLockingRange(0, + OPAL_LOCKINGSTATE::READWRITE, password)) != 0) { + LOG(E) << "Initial setup failed - unable to unlock for read/write"; + return lastRC; + } + + if ((lastRC = configureLockingRange(0, + (DTA_READLOCKINGENABLED | DTA_WRITELOCKINGENABLED), password)) != 0) { + LOG(E) << "Initial setup failed - unable to enable read/write locking"; + return lastRC; + } + + LOG(I) << "Initial setup of TPer complete on " << dev; + LOG(D1) << "Exiting initialSetup()"; + return 0; +} +uint8_t DtaDevEnterprise::readDataStore(char* filename, char* password) +{ + return 0; +} +uint8_t DtaDevEnterprise::writeDataStore(char* filename, char* password) +{ + return 0; +} +uint8_t DtaDevEnterprise::setup_SUM(uint8_t lockingrange, uint64_t start, uint64_t length, char *Admin1Password, char * password) +{ + LOG(D1) << "Entering DtaDevEnterprise::setup_SUM"; + LOG(I) << "setup_SUM not supported on DtaDevEnterprise"; + return 1; +} +uint8_t DtaDevEnterprise::configureLockingRange(uint8_t lockingrange, uint8_t enabled, char * password) +{ + uint8_t lastRC; + LOG(D1) << "Entering DtaDevEnterprise::configureLockingRange()"; + + //** BandMaster0 UID of Table 28 Locking SP Authority table, p. 70 of Enterprise SSC rev 3.00 + std::vector user; + set8(user, OPALUID[OPAL_UID::ENTERPRISE_BANDMASTER0_UID]); + setband(user, lockingrange); + + //** Global_Range UID of Table 33 Locking SP Locking table, p. 84 of Enterprise SSC rev 3.00 + vector object; + set8(object, OPALUID[OPAL_UID::OPAL_LOCKINGRANGE_GLOBAL]); + setband(object, lockingrange); + + session = new DtaSession(this); + if (session == NULL) { + LOG(E) << "Unable to create session object "; + return DTAERROR_OBJECT_CREATE_FAILED; + } + if ((lastRC = session->start(OPAL_UID::ENTERPRISE_LOCKINGSP_UID, password, user)) != 0) { + delete session; + return lastRC; + } + + /* can't use settable because the segate drives require that both the + * read & write lockenabled be changed at the same time. I can find no + * written doc on such a restriction but ..... + */ + vector method; + set8(method, OPALMETHOD[OPAL_METHOD::ESET]); + + DtaCommand *set = new DtaCommand(); + if (set == NULL) { + LOG(E) << "Unable to create command object "; + delete session; + return DTAERROR_OBJECT_CREATE_FAILED; + } + set->reset(object, method); + set->addToken(OPAL_TOKEN::STARTLIST); + set->addToken(OPAL_TOKEN::STARTLIST); + set->addToken(OPAL_TOKEN::ENDLIST); + set->addToken(OPAL_TOKEN::STARTLIST); + set->addToken(OPAL_TOKEN::STARTLIST); + set->addToken(OPAL_TOKEN::STARTNAME); + set->addToken("ReadLockEnabled"); + set->addToken((enabled & DTA_READLOCKINGENABLED) ? OPAL_TRUE : OPAL_FALSE); + set->addToken(OPAL_TOKEN::ENDNAME); + set->addToken(OPAL_TOKEN::STARTNAME); + set->addToken("WriteLockEnabled"); + set->addToken((enabled & DTA_WRITELOCKINGENABLED) ? OPAL_TRUE : OPAL_FALSE); + set->addToken(OPAL_TOKEN::ENDNAME); + set->addToken(OPAL_TOKEN::STARTNAME); + set->addToken("LockOnReset"); + set->addToken(OPAL_TOKEN::STARTLIST); + set->addToken(UINT_00); + set->addToken(OPAL_TOKEN::ENDLIST); + set->addToken(OPAL_TOKEN::ENDNAME); + set->addToken(OPAL_TOKEN::ENDLIST); + set->addToken(OPAL_TOKEN::ENDLIST); + set->addToken(OPAL_TOKEN::ENDLIST); + set->complete(); + + if ((lastRC = session->sendCommand(set, response)) != 0) { + LOG(E) << "Set Failed "; + delete session; + delete set; + return lastRC; + } + delete set; + delete session; + LOG(I) << "Locking range configured " << (uint16_t) enabled; + LOG(D1) << "Exiting DtaDevEnterprise::configureLockingRange()"; + return 0; +} +uint8_t DtaDevEnterprise::rekeyLockingRange(uint8_t lockingrange, char * password) +{ + LOG(D1) << "Entering DtaDevEnterprise::rekeyLockingRange()"; + uint8_t lastRC; + + //** BandMaster0 UID of Table 28 Locking SP Authority table, p. 70 of Enterprise SSC rev 3.00 + vector user; + set8(user, OPALUID[ENTERPRISE_BANDMASTER0_UID]); + setband(user, lockingrange); + + //** Global_Range UID of Table 33 Locking SP Locking table, p. 84 of Enterprise SSC rev 3.00 + vector table; + set8(table, OPALUID[OPAL_UID::OPAL_LOCKINGRANGE_GLOBAL]); + setband(table, lockingrange); + + session = new DtaSession(this); + if (NULL == session) { + LOG(E) << "Unable to create session object "; + return DTAERROR_OBJECT_CREATE_FAILED; + } + if ((lastRC = session->start(OPAL_UID::ENTERPRISE_LOCKINGSP_UID, password, user)) != 0) { + delete session; + return lastRC; + } + if ((lastRC = getTable(table, "ActiveKey", "ActiveKey")) != 0) { + delete session; + return lastRC; + } + std::vector ActiveKey = response.getRawToken(5); + if (is_NULL_UID(ActiveKey)) + { + LOG(I) << "LockingRange" << (uint16_t)lockingrange << " remains in plaintext "; + delete session; + return 0; + } + DtaCommand *rekey = new DtaCommand(); + if (NULL == rekey) { + LOG(E) << "Unable to create command object "; + delete session; + return DTAERROR_OBJECT_CREATE_FAILED; + } + rekey->reset(OPAL_UID::OPAL_AUTHORITY_TABLE, OPAL_METHOD::GENKEY); + rekey->changeInvokingUid(ActiveKey); + rekey->addToken(OPAL_TOKEN::STARTLIST); + rekey->addToken(OPAL_TOKEN::ENDLIST); + rekey->complete(); + if ((lastRC = session->sendCommand(rekey, response)) != 0) { + LOG(E) << "rekeyLockingRange Failed "; + delete rekey; + delete session; + return lastRC; + } + delete rekey; + delete session; + LOG(I) << "LockingRange" << (uint16_t)lockingrange << " reKeyed "; + LOG(D1) << "Exiting DtaDevEnterprise::rekeyLockingRange()"; + return 0; +} +uint8_t DtaDevEnterprise::revertLockingSP(char * password, uint8_t keep) +{ + LOG(D1) << "Entering DtaDevEnterprise::revertLockingSP()"; + if(password == NULL) { LOG(D4) << "Referencing formal parameters " << keep; } + uint8_t lastRC; + DtaCommand *cmd = new DtaCommand(); + if (NULL == cmd) { + LOG(E) << "Unable to create command object "; + return DTAERROR_OBJECT_CREATE_FAILED; + } + session = new DtaSession(this); + if (NULL == session) { + LOG(E) << "Unable to create session object "; + delete cmd; + return DTAERROR_OBJECT_CREATE_FAILED; + } + OPAL_UID uid = OPAL_UID::OPAL_SID_UID; + if ((lastRC = session->start(OPAL_UID::OPAL_ADMINSP_UID, password, uid)) != 0) { + delete cmd; + delete session; + return lastRC; + } + cmd->reset(OPAL_UID::OPAL_THISSP_UID, OPAL_METHOD::REVERTSP); + cmd->addToken(OPAL_TOKEN::STARTLIST); + cmd->addToken(OPAL_TOKEN::STARTNAME); + cmd->addToken("KeepGlobalRangeKey"); + cmd->addToken(keep); + cmd->addToken(OPAL_TOKEN::ENDNAME); + cmd->addToken(OPAL_TOKEN::ENDLIST); + cmd->complete(); + session->expectAbort(); + if ((lastRC = session->sendCommand(cmd, response)) != 0) { + delete cmd; + delete session; + return lastRC; + } + LOG(I) << "revertLockingSP completed successfully"; + delete cmd; + delete session; + LOG(D1) << "Exiting DtaDevEnterprise::revertLockingSP()"; + return 0; +} +uint8_t DtaDevEnterprise::setPassword(char * password, char * userid, char * newpassword) +{ + LOG(D1) << "Entering DtaDevEnterprise::setPassword" ; + uint8_t lastRC; + string defaultPassword; + char *pwd = password, *newpwd = newpassword; + + if (11 > strnlen(userid, 15)) { + LOG(E) << "Invalid Userid " << userid; + return DTAERROR_INVALID_PARAMETER; + } + + std::vector user; + if (!memcmp("BandMaster", userid, 10)) { + uint16_t band = (uint16_t)atoi(&userid[10]); + if (1023 < band) { + LOG(E) << "Invalid Userid " << userid; + return DTAERROR_INVALID_PARAMETER; + } + set8(user, OPALUID[OPAL_UID::ENTERPRISE_BANDMASTER0_UID]); + setband(user, band); + } + else if (!memcmp("EraseMaster", userid, 11)) { + set8(user, OPALUID[OPAL_UID::ENTERPRISE_ERASEMASTER_UID]); + } + else { + LOG(E) << "Invalid Userid " << userid; + return DTAERROR_INVALID_PARAMETER; + } + + if ((password == NULL) || (*password == '\0') || (newpassword == NULL) || + (*newpassword == '\0')) { + if ((lastRC = getDefaultPassword()) != 0) { + LOG(E) << "setPassword failed to retrieve MSID"; + return lastRC; + } + defaultPassword = response.getString(5); + if ((password == NULL) || (*password == '\0')) + pwd = (char *)defaultPassword.c_str(); + + if ((newpassword == NULL) || (*newpassword == '\0')) + newpwd = (char *)defaultPassword.c_str(); + } + + std::vector usercpin; + user2cpin(usercpin, user); + session = new DtaSession(this); + if (session == NULL) { + LOG(E) << "Unable to create session object "; + return DTAERROR_OBJECT_CREATE_FAILED; + } + if ((password == NULL) || (*password == '\0')) + session->dontHashPwd(); + if ((lastRC = session->start(OPAL_UID::ENTERPRISE_LOCKINGSP_UID, pwd, user)) != 0) { + delete session; + return lastRC; + } + + if ((newpassword == NULL) || (*newpassword == '\0')) { + std::vector tmppwd; + + tmppwd.push_back(0xd0); + tmppwd.push_back((uint8_t)strnlen(newpwd, 255)); + for (unsigned int i = 0; i < strnlen(newpwd, 255); i++) { + tmppwd.push_back(newpwd[i]); + } + + if ((lastRC = setTable(usercpin, "PIN", tmppwd)) != 0) { + LOG(E) << "Unable to set user " << userid << " new password "; + delete session; + return lastRC; + } + } else { + std::vector hash; + DtaHashPwd(hash, newpwd, this); + if ((lastRC = setTable(usercpin, "PIN", hash)) != 0) { + LOG(E) << "Unable to set user " << userid << " new password "; + delete session; + return lastRC; + } + } + LOG(I) << userid << " password changed"; + delete session; + LOG(D1) << "Exiting DtaDevEnterprise::setPassword()"; + return 0; +} +uint8_t DtaDevEnterprise::setNewPassword_SUM(char * password, char * userid, char * newpassword) +{ + LOG(D1) << "Entering DtaDevEnterprise::setNewPassword_SUM()"; + LOG(I) << "setNewPassword_SUM is not in the Enterprise SSC and not supported"; + LOG(D1) << "Exiting DtaDevEnterprise::setNewPassword_SUM()"; + return 0; +} +uint8_t DtaDevEnterprise::setMBREnable(uint8_t mbrstate, char * Admin1Password) +{ + LOG(D1) << "Entering DtaDevEnterprise::setMBREnable"; + if (NULL == Admin1Password) { LOG(E) << "This shouldn't happen " << mbrstate; } + LOG(I) << "MBR shadowing is optional in the Enterprise SSC and not supported"; + LOG(D1) << "Exiting DtaDevEnterprise::setMBREnable"; + return 0; +} +uint8_t DtaDevEnterprise::setMBRDone(uint8_t mbrstate, char * Admin1Password) +{ + LOG(D1) << "Entering DtaDevEnterprise::setMBRDone"; + if (NULL == Admin1Password) { LOG(E) << "This shouldn't happen " << mbrstate; } + LOG(I) << "MBR shadowing is optional in the Enterprise SSC and not supported"; + LOG(D1) << "Exiting DtaDevEnterprise::setMBRDone"; + return 0; +} + +uint8_t DtaDevEnterprise::setupLockingRange(uint8_t lockingrange, uint64_t start, uint64_t length, char * password) +{ + uint8_t lastRC; + LOG(D1) << "Entering DtaDevEnterprise::setupLockingRange"; + // look up MaxRanges + uint16_t MaxRanges; + + if ((lastRC = getMaxRanges(password, &MaxRanges)) != 0) { + return (lastRC); + } + if (MaxRanges == 0 || MaxRanges >= 1024) + return DTAERROR_UNSUPORTED_LOCKING_RANGE; + + // make sure lockingrange is in bounds + if (lockingrange > MaxRanges) + { + LOG(E) << "Requested locking range " << lockingrange << " greater than MaxRanges " << MaxRanges; + return DTAERROR_UNSUPORTED_LOCKING_RANGE; + } + + //** BandMaster0 UID of Table 28 Locking SP Authority table, p. 70 of Enterprise SSC rev 3.00 + vector user; + set8(user, OPALUID[OPAL_UID::ENTERPRISE_BANDMASTER0_UID]); + setband(user, lockingrange); + + //** Global_Range UID of Table 33 Locking SP Locking table, p. 84 of Enterprise SSC rev 3.00 + vector object; + set8(object, OPALUID[OPAL_UID::OPAL_LOCKINGRANGE_GLOBAL]); + setband(object, lockingrange); + + vector method; + set8(method, OPALMETHOD[OPAL_METHOD::ESET]); + + DtaCommand *set = new DtaCommand(); + set->reset(object, method); + set->addToken(OPAL_TOKEN::STARTLIST); + set->addToken(OPAL_TOKEN::STARTLIST); + set->addToken(OPAL_TOKEN::ENDLIST); + set->addToken(OPAL_TOKEN::STARTLIST); + set->addToken(OPAL_TOKEN::STARTLIST); + set->addToken(OPAL_TOKEN::STARTNAME); + set->addToken("RangeStart"); + set->addToken(start); + set->addToken(OPAL_TOKEN::ENDNAME); + set->addToken(OPAL_TOKEN::STARTNAME); + set->addToken("RangeLength"); + set->addToken(length); + set->addToken(OPAL_TOKEN::ENDNAME); + set->addToken(OPAL_TOKEN::STARTNAME); + set->addToken("ReadLockEnabled"); + set->addToken(OPAL_TOKEN::OPAL_FALSE); + set->addToken(OPAL_TOKEN::ENDNAME); + set->addToken(OPAL_TOKEN::STARTNAME); + set->addToken("WriteLockEnabled"); + set->addToken(OPAL_TOKEN::OPAL_FALSE); + set->addToken(OPAL_TOKEN::ENDNAME); + set->addToken(OPAL_TOKEN::STARTNAME); + set->addToken("ReadLocked"); + set->addToken(OPAL_TOKEN::OPAL_FALSE); + set->addToken(OPAL_TOKEN::ENDNAME); + set->addToken(OPAL_TOKEN::STARTNAME); + set->addToken("WriteLocked"); + set->addToken(OPAL_TOKEN::OPAL_FALSE); + set->addToken(OPAL_TOKEN::ENDNAME); + set->addToken(OPAL_TOKEN::STARTNAME); + set->addToken("LockOnReset"); + set->addToken(OPAL_TOKEN::STARTLIST); + set->addToken(OPAL_TOKEN::ENDLIST); + set->addToken(OPAL_TOKEN::ENDNAME); + set->addToken(OPAL_TOKEN::ENDLIST); + set->addToken(OPAL_TOKEN::ENDLIST); + set->addToken(OPAL_TOKEN::ENDLIST); + set->complete(); + + session = new DtaSession(this); + if (NULL == session) { + LOG(E) << "Unable to create session object "; + return DTAERROR_OBJECT_CREATE_FAILED; + } + if ((lastRC = session->start(OPAL_UID::ENTERPRISE_LOCKINGSP_UID, password, user)) != 0) { + delete session; + return lastRC; + } + if ((lastRC = session->sendCommand(set, response)) != 0) { + LOG(E) << "setupLockingRange Failed "; + delete set; + delete session; + return lastRC; + } + delete set; + delete session; + LOG(I) << "LockingRange" << (uint16_t)lockingrange << " starting block " << start << + " for " << length << " blocks configured as unlocked range"; + LOG(D1) << "Exiting DtaDevEnterprise::setupLockingRange"; + return 0; +} +uint8_t DtaDevEnterprise::setupLockingRange_SUM(uint8_t lockingrange, uint64_t start, + uint64_t length, char * password) { + LOG(D1) << "Entering DtaDevEnterprise::setupLockingRange_SUM"; + if (0 == lockingrange) { LOG(E) << start << length << password; } + LOG(D1) << "Exiting DtaDevEnterprise::setupLockingRange_SUM"; + return 0; +} +//////////////////////////////////////////////////////////////////////////////// +uint8_t DtaDevEnterprise::listLockingRanges(char * password, int16_t rangeid) +//////////////////////////////////////////////////////////////////////////////// +{ + LOG(D1) << "Entering DtaDevEnterprise::listLockingRanges"; + uint8_t lastRC = 0, failRC = 0; + int one_succeeded = 0; + string defaultPassword; + char *pwd = NULL; + + // if (NULL == password) { LOG(E) << "password NULL"; } + if ((password == NULL) || (*password == '\0')) { + + if ((lastRC = getDefaultPassword()) != 0) { + LOG(E) << __func__ << ": unable to retrieve MSID"; + return lastRC; + } + defaultPassword = response.getString(5); + pwd = (char *)defaultPassword.c_str(); + } else { + pwd = password; + } + + // look up MaxRanges + uint16_t MaxRanges; + + if (rangeid == -1) { + lastRC = getMaxRanges(password, &MaxRanges); + if (lastRC != 0) + return lastRC; + } else + MaxRanges = rangeid; + + if (MaxRanges >= 1024) + return DTAERROR_UNSUPORTED_LOCKING_RANGE; + + if(rangeid == -1) { + LOG(I) << "Maximum ranges supported: " << MaxRanges; + } + + //** BandMaster0 UID of Table 28 Locking SP Authority table, p. 70 of Enterprise SSC rev 3.00 + vector user; + user.clear(); + set8(user, OPALUID[ENTERPRISE_BANDMASTER0_UID]); + + //** Global_Range UID of Table 33 Locking SP Locking table, p. 84 of Enterprise SSC rev 3.00 + vector table; + table.clear(); + set8(table, OPALUID[OPAL_LOCKINGRANGE_GLOBAL]); + + uint16_t start = (rangeid == -1)? 0: rangeid; + for (uint16_t i = start; i <= MaxRanges; i++) + { + uint8_t curRC = 0; + + setband(user, i); + setband(table, i); + + if (output_format == sedutilNormal) { + LOG(I) << "Band[" << i << "]:"; + } + + session = new DtaSession(this); + if (session == NULL) { + LOG(E) << "Unable to create session object "; + return DTAERROR_OBJECT_CREATE_FAILED; + } + if (!defaultPassword.empty()) + session->dontHashPwd(); + + if ((curRC = session->start(OPAL_UID::ENTERPRISE_LOCKINGSP_UID, pwd, user)) != 0) + { + if ((output_format == sedutilNormal) || (rangeid != -1)) { + LOG(I) << " could not establish session for row[" << i << "]"; + } + failRC = curRC; + delete session; + continue; + } + if (getTable(table, "Name", "LockOnReset")) + { + LOG(I) << " row[" << i << "] not found in LOCKING table"; + delete session; + continue; + } + // 00 1 ( F0 ) Start_List + // 01 1 ( F0 ) Start_List + // 02 1 ( F0 ) Start_List + // 03 1 ( F2 ) Start_Name + // 04 5 ( A4 ) 4E 61 6D 65 ("Name") + // 05* 6 ( A5 ) 42 61 6E 64 31 ("Band1") + // 06 1 ( F3 ) End_Name + // 07 1 ( F2 ) Start_Name + // 08 11 ( AA ) 43 6F 6D 6D 6F 6E 4E 61 6D 65 ("CommonName") + // 09* 8 ( A7 ) 4C 6F 63 6B 69 6E 67 ("Locking") + // 10 1 ( F3 ) End_Name + // 11 1 ( F2 ) Start_Name + // 12 11 ( AA ) 52 61 6E 67 65 53 74 61 72 74 ("RangeStart") + // 13* 1 ( 00 ) 0 (0h) + // 14 1 ( F3 ) End_Name + // 15 1 ( F2 ) Start_Name + // 16 12 ( AB ) 52 61 6E 67 65 4C 65 6E 67 74 68 ("RangeLength") + // 17* 1 ( 00 ) 0 (0h) + // 18 1 ( F3 ) End_Name + // 19 1 ( F2 ) Start_Name + // 20 16 ( AF ) 52 65 61 64 4C 6F 63 6B 45 6E 61 62 6C 65 64 ("ReadLockEnabled") + // 21* 1 ( 00 ) 0 (0h) + // 22 1 ( F3 ) End_Name + // 23 1 ( F2 ) Start_Name + // 24 18 ( D0 10 ) 57 72 69 74 65 4C 6F 63 6B 45 6E 61 62 6C 65 64 ("WriteLockEnabled") + // 25* 1 ( 00 ) 0 (0h) + // 26 1 ( F3 ) End_Name + // 27 1 ( F2 ) Start_Name + // 28 11 ( AA ) 52 65 61 64 4C 6F 63 6B 65 64 ("ReadLocked") + // 29* 1 ( 01 ) 1 (1h) + // 30 1 ( F3 ) End_Name + // 31 1 ( F2 ) Start_Name + // 32 12 ( AB ) 57 72 69 74 65 4C 6F 63 6B 65 64 ("WriteLocked") + // 33* 1 ( 01 ) 1 (1h) + // 34 1 ( F3 ) End_Name + // 35 1 ( F2 ) Start_Name + // 36 12 ( AB ) 4C 6F 63 6B 4F 6E 52 65 73 65 74 ("LockOnReset") + // 37 1 ( F0 ) Start_List + // 38 1 ( 00 ) 0 (0h) + // 39 1 ( F1 ) End_List + // 40 1 ( F3 ) End_Name + const std::string Name = response.getString(5+4*0); + const std::string CommonName = response.getString(5+4*1); + const uint64_t RangeStart = response.getUint64(5+4*2); + const uint64_t RangeLength = response.getUint64(5+4*3); + const bool ReadLockEnabled = response.getUint8(5+4*4) != 0; + const bool WriteLockEnabled = response.getUint8(5+4*5) != 0; + const bool ReadLocked = response.getUint8(5+4*6) != 0; + const bool WriteLocked = response.getUint8(5+4*7) != 0; + // LockOnReset list has at least one element + const bool LockOnReset = response.tokenIs(5+4*8) == STARTLIST + && response.tokenIs(5+4*8+1) == DTA_TOKENID_UINT; + delete session; + + if (output_format == sedutilReadable) { + LOG(I) << "Band[" << i << "]: "; + } + + LOG(I) << " Name: " << Name; + LOG(I) << " CommonName: " << CommonName; + LOG(I) << " RangeStart: " << RangeStart; + LOG(I) << " RangeLength: " << RangeLength; + LOG(I) << " ReadLockEnabled: " << ReadLockEnabled; + LOG(I) << " WriteLockEnabled:" << WriteLockEnabled; + LOG(I) << " ReadLocked: " << ReadLocked; + LOG(I) << " WriteLocked: " << WriteLocked; + LOG(I) << " LockOnReset: " << LockOnReset; + + one_succeeded = 1; + } + + // If we're getting the list of ranges and none succeed, that is an error. + // If we're getting one range, return any failure. + if (((rangeid == -1) && (one_succeeded == 0)) + || (rangeid != -1)) + lastRC = failRC; + + LOG(D1) << "Exiting DtaDevEnterprise::listLockingRanges"; + return lastRC; +} + +uint8_t DtaDevEnterprise::setLockingRange(uint8_t lockingrange, uint8_t lockingstate, + char * password) +{ + LOG(D1) << "Entering DtaDevEnterprise::setLockingRange"; + uint8_t lastRC; + + // convert Opal lockingstate to boolean + OPAL_TOKEN locked; + switch (lockingstate) { + case OPAL_LOCKINGSTATE::READWRITE: + locked = OPAL_TOKEN::OPAL_FALSE; + break; + case OPAL_LOCKINGSTATE::READONLY: + LOG(E) << "Read Only locking state is unsupported in Enterprise SSC"; + return DTAERROR_INVALID_PARAMETER; + case OPAL_LOCKINGSTATE::LOCKED: + locked = OPAL_TOKEN::OPAL_TRUE; + break; + default: + LOG(E) << "Invalid locking state for setLockingRange (RW=1, LOCKED=3)"; + return DTAERROR_INVALID_PARAMETER; + } + + // look up MaxRanges + uint16_t MaxRanges; + + if ((lastRC = getMaxRanges(password, &MaxRanges)) != 0) { + return lastRC; + } + if (MaxRanges == 0 || MaxRanges >= 1024) + return DTAERROR_UNSUPORTED_LOCKING_RANGE; + + // make sure lockingrange is in bounds + if (lockingrange > MaxRanges) + { + LOG(E) << "Requested locking range " << lockingrange << " greater than MaxRanges " << MaxRanges; + return DTAERROR_UNSUPORTED_LOCKING_RANGE; + } + + //** BandMaster0 UID of Table 28 Locking SP Authority table, p. 70 of Enterprise SSC rev 3.00 + vector user; + set8(user, OPALUID[OPAL_UID::ENTERPRISE_BANDMASTER0_UID]); + setband(user, lockingrange); + + //** Band0 UID of Table 33 Locking SP Locking table, p. 84 of Enterprise SSC rev 3.00 + vector object; + set8(object, OPALUID[OPAL_UID::OPAL_LOCKINGRANGE_GLOBAL]); + setband(object, lockingrange); + + vector method; + set8(method, OPALMETHOD[OPAL_METHOD::ESET]); + + DtaCommand *set = new DtaCommand(); + set->reset(object, method); + set->addToken(OPAL_TOKEN::STARTLIST); + set->addToken(OPAL_TOKEN::STARTLIST); + set->addToken(OPAL_TOKEN::ENDLIST); + set->addToken(OPAL_TOKEN::STARTLIST); + set->addToken(OPAL_TOKEN::STARTLIST); + set->addToken(OPAL_TOKEN::STARTNAME); + set->addToken("WriteLocked"); + set->addToken(locked); + set->addToken(OPAL_TOKEN::ENDNAME); + set->addToken(OPAL_TOKEN::STARTNAME); + set->addToken("ReadLocked"); + set->addToken(locked); + set->addToken(OPAL_TOKEN::ENDNAME); + set->addToken(OPAL_TOKEN::ENDLIST); + set->addToken(OPAL_TOKEN::ENDLIST); + set->addToken(OPAL_TOKEN::ENDLIST); + set->complete(); + session = new DtaSession(this); + if (session == NULL) { + LOG(E) << "Unable to create session object "; + return DTAERROR_OBJECT_CREATE_FAILED; + } + if ((lastRC = session->start(OPAL_UID::ENTERPRISE_LOCKINGSP_UID, password, user)) +!= 0) { + delete session; + return lastRC; + } + if ((lastRC = session->sendCommand(set, response)) != 0) { + LOG(E) << "Set Failed "; + delete session; + delete set; + return lastRC; + } + delete set; + delete session; + LOG(I) << "Locking range Read/Write set " << (uint16_t)locked; + LOG(D1) << "Exiting DtaDevEnterprise::setLockingRange"; + return 0; +} +uint8_t DtaDevEnterprise::setLockingRange_SUM(uint8_t lockingrange, uint8_t lockingstate, + char * password) { + LOG(D1) << "Entering DtaDevEnterprise::setLockingRange_SUM()"; + LOG(E) << "setLockingRange_SUM not implemented"; + LOG(D1) << "Exiting DtaDevEnterprise::setLockingRange_SUM()"; + return DTAERROR_INVALID_PARAMETER; +} +uint8_t DtaDevEnterprise::enableUser(char * password, char * userid, OPAL_TOKEN status) +{ + LOG(D1) << "Entering DtaDevEnterprise::enableUser"; + LOG(E) << "enableUser not implemented"; + if (!password && !userid) { LOG(E) << "Formal Parameters"; } + LOG(D1) << "Exiting DtaDevEnterprise::enableUser()"; + return DTAERROR_INVALID_PARAMETER; +} +uint8_t DtaDevEnterprise::revertTPer(char * password, uint8_t PSID, uint8_t AdminSP) +{ + LOG(D1) << "Entering DtaDevEnterprise::revertTPer()"; + if (password == NULL) { LOG(D4) << "Referencing formal parameters " << PSID; } + uint8_t lastRC; + DtaCommand *cmd = new DtaCommand(); + if (NULL == cmd) { + LOG(E) << "Unable to create command object "; + return DTAERROR_OBJECT_CREATE_FAILED; + } + session = new DtaSession(this); + if (NULL == session) { + LOG(E) << "Unable to create session object "; + delete cmd; + return DTAERROR_OBJECT_CREATE_FAILED; + } + OPAL_UID uid = OPAL_UID::OPAL_SID_UID; + if (PSID) { + session->dontHashPwd(); // PSID pwd should be passed as entered + uid = OPAL_UID::OPAL_PSID_UID; + } + if ((lastRC = session->start(OPAL_UID::OPAL_ADMINSP_UID, password, uid)) != 0) { + delete cmd; + delete session; + return lastRC; + } + if (AdminSP) + cmd->reset(OPAL_UID::OPAL_ADMINSP_UID, OPAL_METHOD::REVERT); + else + cmd->reset(OPAL_UID::OPAL_THISSP_UID, OPAL_METHOD::REVERTSP); + cmd->addToken(OPAL_TOKEN::STARTLIST); + cmd->addToken(OPAL_TOKEN::ENDLIST); + cmd->complete(); + session->expectAbort(); + if ((lastRC = session->sendCommand(cmd, response)) != 0) { + delete cmd; + delete session; + return lastRC; + } + LOG(I) << "revertTper completed successfully"; + delete cmd; + delete session; + LOG(D1) << "Exiting DtaDevEnterprise::revertTPer()"; + return 0; +} +uint8_t DtaDevEnterprise::eraseLockingRange(uint8_t lockingrange, char * password) +{ + uint8_t lastRC; + string defaultPassword; + char *pwd = NULL; + LOG(D1) << "Entering DtaDevEnterprise::eraseLockingRange"; + + // look up MaxRanges + uint16_t MaxRanges = 0; + + if ((password == NULL) || (*password == '\0')) { + + if ((lastRC = getDefaultPassword()) != 0) { + LOG(E) << __func__ << ": unable to retrieve MSID"; + return lastRC; + } + defaultPassword = response.getString(5); + pwd = (char *)defaultPassword.c_str(); + } else { + pwd = password; + } + + if ((lastRC = getMaxRanges(pwd, &MaxRanges)) != 0) { + return lastRC; + } + if (MaxRanges == 0 || MaxRanges >= 1024) + return DTAERROR_UNSUPORTED_LOCKING_RANGE; + + // make sure lockingrange is in bounds + if (lockingrange > MaxRanges) + { + LOG(E) << "Requested locking range " << lockingrange << " greater than MaxRanges " << MaxRanges; + return DTAERROR_UNSUPORTED_LOCKING_RANGE; + } + + //** EraseMaster UID of Table 28 Locking SP Authority table, p. 70 of Enterprise SSC rev 3.00 + vector user; + set8(user, OPALUID[OPAL_UID::ENTERPRISE_ERASEMASTER_UID]); + + //** Band0 UID of Table 33 Locking SP Locking table, p. 84 of Enterprise SSC rev 3.00 + vector object; + set8(object, OPALUID[OPAL_UID::OPAL_LOCKINGRANGE_GLOBAL]); + setband(object, lockingrange); + + vector method; + set8(method, OPALMETHOD[OPAL_METHOD::ERASE]); + + DtaCommand *erase = new DtaCommand(); + if (erase == NULL) { + LOG(E) << "Unable to create command object "; + return DTAERROR_OBJECT_CREATE_FAILED; + } + erase->reset(object, method); + erase->addToken(OPAL_TOKEN::STARTLIST); + erase->addToken(OPAL_TOKEN::ENDLIST); + erase->complete(); + + session = new DtaSession(this); + if (NULL == session) { + LOG(E) << "Unable to create session object "; + return DTAERROR_OBJECT_CREATE_FAILED; + } + if (!defaultPassword.empty()) + session->dontHashPwd(); + + if ((lastRC = session->start(OPAL_UID::ENTERPRISE_LOCKINGSP_UID, pwd, user)) != 0) { + delete session; + return lastRC; + } + if ((lastRC = session->sendCommand(erase, response)) != 0) { + LOG(E) << "eraseLockingRange Failed "; + delete erase; + delete session; + return lastRC; + } + delete erase; + delete session; + LOG(I) << "LockingRange" << (uint16_t)lockingrange << " erased"; + LOG(D1) << "Exiting DtaDevEnterprise::eraseLockingRange"; + return 0; +} +uint8_t DtaDevEnterprise::loadPBA(char * password, char * filename) { + LOG(D1) << "Entering DtaDevEnterprise::loadPBAimage()" << filename << " " << dev; + if (password == NULL) { LOG(D4) << "Referencing formal parameters " << filename; } + LOG(I) << "loadPBA is not implemented. It is not a mandatory part of "; + LOG(I) << "the enterprise SSC "; + LOG(D1) << "Exiting DtaDevEnterprise::loadPBAimage()"; + return DTAERROR_INVALID_PARAMETER; +} +uint8_t DtaDevEnterprise::activateLockingSP(char * password) +{ + LOG(D1) << "Entering DtaDevEnterprise::activateLockingSP()"; + if (password == NULL) { LOG(D4) << "Referencing formal parameters "; } + LOG(E) << "activate Locking SP is not a part of the Enterprise SSC "; + LOG(D1) << "Exiting DtaDevEnterprise::activatLockingSP()"; + return DTAERROR_INVALID_PARAMETER; +} +uint8_t DtaDevEnterprise::activateLockingSP_SUM(uint8_t lockingrange, char * password) +{ + LOG(D1) << "Entering DtaDevEnterprise::activateLockingSP_SUM()"; + if (password == NULL) { LOG(D4) << "Referencing formal parameters "; } + LOG(E) << "activate Locking SP SUM is not a part of the Enterprise SSC "; + LOG(D1) << "Exiting DtaDevEnterprise::activateLockingSP_SUM()"; + return DTAERROR_INVALID_PARAMETER; +} +uint8_t DtaDevEnterprise::eraseLockingRange_SUM(uint8_t lockingrange, char * password) +{ + LOG(D1) << "Entering DtaDevEnterprise::eraseLockingRange_SUM()"; + if (password == NULL) { LOG(D4) << "Referencing formal parameters "; } + LOG(E) << "Erase Locking Range SUM is not a part of the Enterprise SSC "; + LOG(D1) << "Exiting DtaDevEnterprise::eraseLockingRange_SUM()"; + return DTAERROR_INVALID_PARAMETER; +} +uint8_t DtaDevEnterprise::takeOwnership(char * newpassword) +{ + string defaultPassword; + uint8_t lastRC; + + LOG(D1) << "Entering DtaDevEnterprise::takeOwnership()"; + if ((lastRC = getDefaultPassword()) != 0) { + LOG(E) << "takeOwnership failed unable to retrieve MSID"; + return lastRC; + } + defaultPassword = response.getString(5); + if ((lastRC = setSIDPassword((char *)defaultPassword.c_str(), newpassword, 0)) != 0) { + LOG(E) << "takeOwnership failed unable to set new SID password"; + return lastRC; + } + if ((lastRC = initLSPUsers((char *)defaultPassword.c_str(), newpassword)) != 0) { + LOG(E) << "takeOwnership failed unable to set Locking SP user passwords"; + return lastRC; + } + LOG(I) << "takeOwnership complete"; + LOG(D1) << "Exiting takeOwnership()"; + return 0; +} +//////////////////////////////////////////////////////////////////////////////// +uint8_t DtaDevEnterprise::setBandsEnabled(int16_t lockingrange, char * password) +//////////////////////////////////////////////////////////////////////////////// +{ + uint8_t lastRC = 0; + LOG(D1) << "Entering DtaDevEnterprise::eraseLockingRange"; + + // look up MaxRanges + uint16_t MaxRanges = 0; + + if ((lastRC = getMaxRanges(password, &MaxRanges)) != 0) { + return lastRC; + } + if (MaxRanges >= 1024) + return DTAERROR_UNSUPORTED_LOCKING_RANGE; + + // calculate starting and ending bands + int lo, hi; + if (lockingrange < 0) + { + lo = 0; + hi = MaxRanges; + } + else if (lockingrange > MaxRanges) + { + LOG(E) << "Requested locking range " << lockingrange << " greater than MaxRanges " << MaxRanges; + return DTAERROR_UNSUPORTED_LOCKING_RANGE; + } + else + { + lo = lockingrange; + hi = lockingrange; + } + + // get password (usually MSID) + string pwd; + const bool useMSID = password == NULL || *password == '\0'; + if (!useMSID) + { + pwd = password; + } + else + { + if ((lastRC = getDefaultPassword()) != 0) + return lastRC; + pwd = response.getString(5); + } + + vector erasemaster; + set8(erasemaster, OPALUID[OPAL_UID::ENTERPRISE_ERASEMASTER_UID]); + + //** BandMaster0 UID of Table 28 Locking SP Authority table, p. 70 of Enterprise SSC rev 3.00 + vector object; + set8(object, OPALUID[OPAL_UID::ENTERPRISE_BANDMASTER0_UID]); + + // method is enterprise set + vector method; + set8(method, OPALMETHOD[OPAL_METHOD::ESET]); + + // set Enabled=TRUE in BandMaster[n] row of (Table 28) Locking SP Authority + for(int n=lo; n<=hi && lastRC==0; n++) + { + // BandMaster[n] row + setband(object, (uint16_t) n); + + // command to set Enabled column + DtaCommand *cmd = new DtaCommand(); + if (cmd == NULL) { + LOG(E) << "Unable to create command object "; + return DTAERROR_OBJECT_CREATE_FAILED; + } + cmd->reset(object, method); + cmd->addToken(OPAL_TOKEN::STARTLIST); + cmd->addToken(OPAL_TOKEN::STARTLIST); + cmd->addToken(OPAL_TOKEN::ENDLIST); + cmd->addToken(OPAL_TOKEN::STARTLIST); + cmd->addToken(OPAL_TOKEN::STARTLIST); + cmd->addToken(OPAL_TOKEN::STARTNAME); + cmd->addToken("Enabled"); + cmd->addToken(OPAL_TRUE); + cmd->addToken(OPAL_TOKEN::ENDNAME); + cmd->addToken(OPAL_TOKEN::ENDLIST); + cmd->addToken(OPAL_TOKEN::ENDLIST); + cmd->addToken(OPAL_TOKEN::ENDLIST); + cmd->complete(); + + // create session to use with erasemaster + session = new DtaSession(this); + if (session == NULL) { + LOG(E) << "Unable to create session object "; + delete cmd; + return DTAERROR_OBJECT_CREATE_FAILED; + } + + // MSID ? + if (useMSID) session->dontHashPwd(); + + // start session + lastRC = session->start(OPAL_UID::ENTERPRISE_LOCKINGSP_UID, (char *)pwd.c_str(), erasemaster); + if (lastRC == 0) + { + // send command + lastRC = session->sendCommand(cmd, response); + } + + delete cmd; + delete session; + } + + return lastRC; +} + +uint8_t DtaDevEnterprise::initLSPUsers(char * defaultPassword, char * newPassword) +{ + vector user, usercpin, hash, erasemaster, table; + uint8_t lastRC; + LOG(D1) << "Entering DtaDevEnterprise::initLSPUsers()"; + +// do erasemaster + session = new DtaSession(this); + if (session == NULL) { + LOG(E) << "Unable to create session object "; + return DTAERROR_OBJECT_CREATE_FAILED; + } + session->dontHashPwd(); + set8(erasemaster, OPALUID[OPAL_UID::ENTERPRISE_ERASEMASTER_UID]); + if ((lastRC = session->start(OPAL_UID::ENTERPRISE_LOCKINGSP_UID, defaultPassword, erasemaster)) != 0) { + delete session; + return lastRC; + } + DtaHashPwd(hash, newPassword, this); + user2cpin(usercpin, erasemaster); + if ((lastRC = setTable(usercpin, "PIN", hash)) != 0) { + LOG(E) << "Unable to set new EraseMaster password "; + delete session; + return lastRC; + } + LOG(I) << "EraseMaster password set"; + delete session; + // look up MaxRanges + uint16_t MaxRanges = 0; + if ((lastRC = getMaxRanges(NULL, &MaxRanges)) != 0) { + return lastRC; + } + if (MaxRanges == 0 || MaxRanges >= 1024) + return DTAERROR_UNSUPORTED_LOCKING_RANGE; + + LOG(I) << "Maximum ranges supported " << MaxRanges; +// do bandmasters + set8(user, OPALUID[ENTERPRISE_BANDMASTER0_UID]); + for (uint16_t i = 0; i <= MaxRanges; i++) { + setband(user, i); + LOG(D3) << "initializing BandMaster" << (uint16_t) i; + session = new DtaSession(this); + if (session == NULL) { + LOG(E) << "Unable to create session object "; + return DTAERROR_OBJECT_CREATE_FAILED; + } + session->dontHashPwd(); + if ((lastRC = session->start(OPAL_UID::ENTERPRISE_LOCKINGSP_UID, defaultPassword, user)) != 0) { + delete session; + // We only return failure if we fail to set BandMaster0. + if (i == 0) { + return lastRC; + } else { + continue; + } + } + DtaHashPwd(hash, newPassword, this); + user2cpin(usercpin, user); + if ((lastRC = setTable(usercpin, "PIN", hash)) != 0) { + LOG(E) << "Unable to set BandMaster" << (uint16_t) i << " new password "; + // We only return failure if we fail to set BandMaster0. + if (i == 0) { + delete session; + return lastRC; + } + } else { + LOG(I) << "BandMaster" << (uint16_t) i << " password set"; + } + delete session; + } + LOG(D1) << "Exiting DtaDevEnterprise::initLSPUsers()"; + return 0; +} +uint8_t DtaDevEnterprise::getDefaultPassword() +{ + LOG(D1) << "Entering DtaDevEnterprise::getDefaultPassword()"; + uint8_t lastRC; + vector hash; + session = new DtaSession(this); + if (session == NULL) { + LOG(E) << "Unable to create session object "; + return DTAERROR_OBJECT_CREATE_FAILED; + } + if ((lastRC = session->start(OPAL_UID::OPAL_ADMINSP_UID)) != 0) { + LOG(E) << "Unable to start Unauthenticated session " << dev; + delete session; + return lastRC; + } + vector table; + table. push_back(OPAL_SHORT_ATOM::BYTESTRING8); + for (int i = 0; i < 8; i++) { + table.push_back(OPALUID[OPAL_UID::OPAL_C_PIN_MSID][i]); + } + if ((lastRC = getTable(table, "PIN", "PIN")) != 0) { + delete session; + return lastRC; + } + delete session; + LOG(D1) << "Exiting getDefaultPassword()"; + return 0; +} +uint8_t DtaDevEnterprise::printDefaultPassword() +{ + const uint8_t rc = getDefaultPassword(); + if (rc) { + LOG(E) << "unable to retrieve MSID"; + return rc; + } + string defaultPassword = response.getString(5); + fprintf(stdout, "MSID: %s\n", (char *)defaultPassword.c_str()); + return 0; +} + + +uint8_t DtaDevEnterprise::setSIDPassword(char * oldpassword, char * newpassword, + uint8_t hasholdpwd, uint8_t hashnewpwd) +{ + LOG(D1) << "Entering DtaDevEnterprise::setSIDPassword()"; + uint8_t lastRC; + + vector user; + set8(user, OPALUID[OPAL_SID_UID]); + + vector usercpin; + set8(usercpin, OPALUID[OPAL_C_PIN_SID]); + + if (*oldpassword == '\0') + { + if ((lastRC = getDefaultPassword()) != 0) { + LOG(E) << "setPassword failed to retrieve MSID"; + return lastRC; + } + string defaultPassword = response.getString(5); + session = new DtaSession(this); + if (session == NULL) { + LOG(E) << "Unable to create session object "; + return DTAERROR_OBJECT_CREATE_FAILED; + } + session->dontHashPwd(); + if ((lastRC = session->start(OPAL_UID::OPAL_ADMINSP_UID, (char *)defaultPassword.c_str(), user)) != 0) { + delete session; + return lastRC; + } + } + else + { + session = new DtaSession(this); + if (session == NULL) { + LOG(E) << "Unable to create session object "; + return DTAERROR_OBJECT_CREATE_FAILED; + } + session->dontHashPwd(); + if (!hasholdpwd) session->dontHashPwd(); + if ((lastRC = session->start(OPAL_UID::OPAL_ADMINSP_UID, oldpassword, user)) != 0) { + delete session; + return lastRC; + } + } + vector hash; + if (hashnewpwd) + { + DtaHashPwd(hash, newpassword, this); + } + else + { + hash.push_back(0xd0); + hash.push_back((uint8_t)strnlen(newpassword, 255)); + for (uint16_t i = 0; i < strnlen(newpassword, 255); i++) + { + hash.push_back(newpassword[i]); + } + } + if ((lastRC = setTable(usercpin, "PIN", hash)) != 0) { + LOG(E) << "Unable to set new SID password "; + delete session; + return lastRC; + } + delete session; + LOG(D1) << "Exiting DtaDevEnterprise::setSIDPassword()"; + return 0; +} +uint8_t DtaDevEnterprise::setTable(vector table, const char *name, + OPAL_TOKEN value) +{ + vector token; + token.push_back((uint8_t) value); + return(setTable(table, name, token)); +} +uint8_t DtaDevEnterprise::setTable(vector table, const char *name, + vector value) +{ + LOG(D1) << "Entering DtaDevEnterprise::setTable"; + uint8_t lastRC; + DtaCommand *set = new DtaCommand(); + if (set == NULL) { + LOG(E) << "Unable to create command object "; + return DTAERROR_OBJECT_CREATE_FAILED; + } + set->reset(OPAL_UID::OPAL_AUTHORITY_TABLE, OPAL_METHOD::ESET); + set->changeInvokingUid(table); + set->addToken(OPAL_TOKEN::STARTLIST); + set->addToken(OPAL_TOKEN::STARTLIST); + set->addToken(OPAL_TOKEN::ENDLIST); + set->addToken(OPAL_TOKEN::STARTLIST); + set->addToken(OPAL_TOKEN::STARTLIST); + set->addToken(OPAL_TOKEN::STARTNAME); + set->addToken(name); + set->addToken(value); + set->addToken(OPAL_TOKEN::ENDNAME); + set->addToken(OPAL_TOKEN::ENDLIST); + set->addToken(OPAL_TOKEN::ENDLIST); + set->addToken(OPAL_TOKEN::ENDLIST); + set->complete(); + if ((lastRC = session->sendCommand(set, response)) != 0) { + LOG(E) << "Set Failed "; + delete set; + return lastRC; + } + delete set; + LOG(D1) << "Leaving DtaDevEnterprise::setTable"; + return 0; +} +uint8_t DtaDevEnterprise::getTable(vector table, const char * startcol, + const char * endcol) +{ + LOG(D1) << "Entering DtaDevEnterprise::getTable"; + uint8_t lastRC; + DtaCommand *get = new DtaCommand(); + if (get == NULL) { + LOG(E) << "Unable to create command object "; + return DTAERROR_OBJECT_CREATE_FAILED; + } + get->reset(OPAL_UID::OPAL_AUTHORITY_TABLE, OPAL_METHOD::EGET); + get->changeInvokingUid(table); + get->addToken(OPAL_TOKEN::STARTLIST); + get->addToken(OPAL_TOKEN::STARTLIST); + get->addToken(OPAL_TOKEN::STARTNAME); + get->addToken("startColumn"); + get->addToken(startcol); + get->addToken(OPAL_TOKEN::ENDNAME); + get->addToken(OPAL_TOKEN::STARTNAME); + get->addToken("endColumn"); + get->addToken(endcol); + get->addToken(OPAL_TOKEN::ENDNAME); + get->addToken(OPAL_TOKEN::ENDLIST); + get->addToken(OPAL_TOKEN::ENDLIST); + get->complete(); + if ((lastRC = session->sendCommand(get, response)) != 0) { + delete get; + return lastRC; + } + delete get; + return 0; +} +uint16_t DtaDevEnterprise::comID() +{ + LOG(D1) << "Entering DtaDevEnterprise::comID()"; + return disk_info.Enterprise_basecomID; +} +uint8_t DtaDevEnterprise::exec(DtaCommand * cmd, DtaResponse & resp, uint8_t protocol) +{ + uint8_t rc = 0; + OPALHeader * hdr = (OPALHeader *) cmd->getCmdBuffer(); + LOG(D3) << endl << "Dumping command buffer"; + IFLOG(D) DtaAnnotatedDump(IF_SEND, cmd->getCmdBuffer(), cmd->outputBufferSize()); + IFLOG(D3) DtaHexDump(cmd->getCmdBuffer(), SWAP32(hdr->cp.length) + sizeof (OPALComPacket)); + rc = sendCmd(IF_SEND, protocol, comID(), cmd->getCmdBuffer(), cmd->outputBufferSize()); + if (0 != rc) { + LOG(E) << "Command failed on send " << (uint16_t) rc; + return rc; + } + hdr = (OPALHeader *) cmd->getRespBuffer(); + do { + //LOG(I) << "read loop"; + osmsSleep(25); + memset(cmd->getRespBuffer(), 0, MIN_BUFFER_LENGTH); + rc = sendCmd(IF_RECV, protocol, comID(), cmd->getRespBuffer(), MIN_BUFFER_LENGTH); + + } + while ((0 != hdr->cp.outstandingData) && (0 == hdr->cp.minTransfer)); + LOG(D3) << std::endl << "Dumping reply buffer"; + IFLOG(D) DtaAnnotatedDump(IF_RECV, cmd->getRespBuffer(), SWAP32(hdr->cp.length) + sizeof (OPALComPacket)); + IFLOG(D3) DtaHexDump(cmd->getRespBuffer(), SWAP32(hdr->cp.length) + sizeof (OPALComPacket)); + if (0 != rc) { + LOG(E) << "Command failed on recv" << (uint16_t) rc; + return rc; + } + resp.init(cmd->getRespBuffer()); + return 0; +} +uint8_t DtaDevEnterprise::properties() +{ + LOG(D1) << "Entering DtaDevEnterprise::properties()"; + uint8_t lastRC; + session = new DtaSession(this); // use the session IO without starting a session + if (session == NULL) { + LOG(E) << "Unable to create session object "; + return DTAERROR_OBJECT_CREATE_FAILED; + } + DtaCommand *props = new DtaCommand(OPAL_UID::OPAL_SMUID_UID, OPAL_METHOD::PROPERTIES); + if (props == NULL) { + LOG(E) << "Unable to create command object "; + delete session; + return DTAERROR_OBJECT_CREATE_FAILED; + } + props->addToken(OPAL_TOKEN::STARTLIST); + props->addToken(OPAL_TOKEN::STARTNAME); + props->addToken("HostProperties"); + props->addToken(OPAL_TOKEN::STARTLIST); + props->addToken(OPAL_TOKEN::STARTNAME); + props->addToken("MaxComPacketSize"); + props->addToken(2048); + props->addToken(OPAL_TOKEN::ENDNAME); + props->addToken(OPAL_TOKEN::STARTNAME); + props->addToken("MaxPacketSize"); + props->addToken(2028); + props->addToken(OPAL_TOKEN::ENDNAME); + props->addToken(OPAL_TOKEN::STARTNAME); + props->addToken("MaxIndTokenSize"); + props->addToken(1992); + props->addToken(OPAL_TOKEN::ENDNAME); + props->addToken(OPAL_TOKEN::STARTNAME); + props->addToken("MaxPackets"); + props->addToken(1); + props->addToken(OPAL_TOKEN::ENDNAME); + props->addToken(OPAL_TOKEN::STARTNAME); + props->addToken("MaxSubpackets"); + props->addToken(1); + props->addToken(OPAL_TOKEN::ENDNAME); + props->addToken(OPAL_TOKEN::STARTNAME); + props->addToken("MaxMethods"); + props->addToken(1); + props->addToken(OPAL_TOKEN::ENDNAME); + props->addToken(OPAL_TOKEN::ENDLIST); + props->addToken(OPAL_TOKEN::ENDNAME); + props->addToken(OPAL_TOKEN::ENDLIST); + props->complete(); + if ((lastRC = session->sendCommand(props, propertiesResponse)) != 0) { + delete props; + return lastRC; + } + disk_info.Properties = 1; + delete props; + LOG(D1) << "Leaving DtaDevEnterprise::properties()"; + return 0; +} +void DtaDevEnterprise::puke() +{ + + LOG(D1) << "Entering DtaDevEnterprise::puke()"; + DtaDev::puke(); + if (disk_info.Properties) { + uint32_t i = 0, j = 0; + + cout << std::endl << "TPer Properties: " << std::endl; + for (i = 0, j = 1; i < propertiesResponse.getTokenCount(); i++) { + if (OPAL_TOKEN::ENDLIST == propertiesResponse.tokenIs(i)) { + if (OPAL_TOKEN::STARTNAME == propertiesResponse.tokenIs(i + 1)) { + cout << std::endl << "Host Properties: " << std::endl; + i += 2; + j = 1; + continue; + } + else { + break; + } + } + if (OPAL_TOKEN::STARTNAME == propertiesResponse.tokenIs(i)) { + if (OPAL_TOKEN::DTA_TOKENID_BYTESTRING == propertiesResponse.tokenIs(i + 1)) { + cout << " " << propertiesResponse.getString(i + 1) << " = " << propertiesResponse.getUint64(i + 2); + i += 2; + j++; + if (!(j % 3)) cout << std::endl; + } + } + } + if ((j % 3) != 0) + cout << std::endl; + } +} +uint8_t DtaDevEnterprise::rawCmd(char *sp, char *hexauth, char *pass, + char *hexinvokingUID, char *hexmethod,char *hexparms) +{ + LOG(D1) << "Entering DtaDevEnterprise::rawCmd"; + LOG(D1) << sp << " " << hexauth << " " << pass << " " ; + LOG(D1) << hexinvokingUID << " " << hexmethod << " " << hexparms; + uint8_t lastRC; + vector authority, object, invokingUID, method, parms; + uint8_t work; + if (16 != strnlen(hexauth, 32)) { + LOG(E) << "Authority must be 16 byte ascii string of hex authority uid"; + return DTAERROR_INVALID_PARAMETER; + } + authority.push_back(OPAL_SHORT_ATOM::BYTESTRING8); + for (uint32_t i = 0; i < 16; i += 2) { + work = hexauth[i] & 0x40 ? 16 * ((hexauth[i] & 0xf) + 9) : 16 * (hexauth[i] & 0x0f); + work += hexauth[i + 1] & 0x40 ? (hexauth[i + 1] & 0xf) + 9 : hexauth[i + 1] & 0x0f; + authority.push_back(work); + } + if (16 != strnlen(hexinvokingUID, 32)) { + LOG(E) << "invoker must be 16 byte ascii string of invoking uid"; + return DTAERROR_INVALID_PARAMETER; + } + invokingUID.push_back(OPAL_SHORT_ATOM::BYTESTRING8); + for (uint32_t i = 0; i < 16; i += 2) { + work = hexinvokingUID[i] & 0x40 ? 16 * ((hexinvokingUID[i] & 0xf) + 9) : 16 * (hexinvokingUID[i] & 0x0f); + work += hexinvokingUID[i + 1] & 0x40 ? (hexinvokingUID[i + 1] & 0xf) + 9 : hexinvokingUID[i + 1] & 0x0f; + invokingUID.push_back(work); + } + if (16 != strnlen(hexmethod, 32)) { + LOG(E) << "invoker must be 16 byte ascii string of method uid"; + return DTAERROR_INVALID_PARAMETER; + } + method.push_back(OPAL_SHORT_ATOM::BYTESTRING8); + for (uint32_t i = 0; i < 16; i += 2) { + work = hexmethod[i] & 0x40 ? 16 * ((hexmethod[i] & 0xf) + 9) : 16 * (hexmethod[i] & 0x0f); + work += hexmethod[i + 1] & 0x40 ? (hexmethod[i + 1] & 0xf) + 9 : hexmethod[i + 1] & 0x0f; + method.push_back(work); + } + if (1020 < strnlen(hexparms, 1024)) { + LOG(E) << "Parmlist limited to 1020 characters"; + return DTAERROR_INVALID_PARAMETER; + } + if (strnlen(hexparms, 1024) % 2) { + LOG(E) << "Parmlist must be even number of bytes"; + return DTAERROR_INVALID_PARAMETER; + } + + for (uint32_t i = 0; i < strnlen(hexparms, 1024); i += 2) { + work = hexparms[i] & 0x40 ? 16 * ((hexparms[i] & 0xf) + 9) : 16 * (hexparms[i] & 0x0f); + work += hexparms[i + 1] & 0x40 ? (hexparms[i + 1] & 0xf) + 9 : hexparms[i + 1] & 0x0f; + parms.push_back(work); + } + DtaCommand *cmd = new DtaCommand(); + if (cmd == NULL) { + LOG(E) << "Unable to create command object "; + return DTAERROR_OBJECT_CREATE_FAILED; + } + cmd->reset(OPAL_UID::OPAL_AUTHORITY_TABLE, method); + cmd->changeInvokingUid(invokingUID); + cmd->addToken(parms); + cmd->complete(); + session = new DtaSession(this); + if (session == NULL) { + LOG(E) << "Unable to create session object "; + delete cmd; + return DTAERROR_OBJECT_CREATE_FAILED; + } + if ((lastRC = session->start((OPAL_UID) atoi(sp), pass, authority)) != 0) { + delete cmd; + delete session; + return lastRC; + } + LOG(I) << "Command:"; + cmd->dumpCommand(); + if ((lastRC = session->sendCommand(cmd, response)) != 0) { + delete cmd; + delete session; + return lastRC; + } + LOG(I) << "Response:"; + cmd->dumpResponse(); + delete cmd; + delete session; + LOG(D1) << "Exiting DtaDevEnterprise::rawCmd"; + return 0; +} +uint8_t DtaDevEnterprise::objDump(char *sp, char * auth, char *pass, + char * objID) +{ + LOG(D1) << "Entering DtaDevEnterprise::objDump"; + LOG(D1) << sp << " " << auth << " " << pass << " " << objID; + DtaCommand *get = new DtaCommand(); + vector authority, object; + uint8_t work; + if (16 != strnlen(auth, 32)) { + LOG(E) << "Authority must be 16 byte ascii string of hex authority uid"; + return 0xff; + } + if (16 != strnlen(objID, 32)) { + LOG(E) << "ObjectID must be 16 byte ascii string of hex object uid"; + return 0xff; + } + authority.push_back(OPAL_SHORT_ATOM::BYTESTRING8); + for (uint32_t i = 0; i < 16; i += 2) { + work = auth[i] & 0x40 ? 16 * ((auth[i] & 0xf) + 9) : 16 * (auth[i] & 0x0f); + work += auth[i + 1] & 0x40 ? (auth[i + 1] & 0xf) + 9 : auth[i + 1] & 0x0f; + authority.push_back(work); + } + object.push_back(OPAL_SHORT_ATOM::BYTESTRING8); + for (uint32_t i = 0; i < 16; i += 2) { + work = objID[i] & 0x40 ? 16 * ((objID[i] & 0xf) + 9) : 16 * (objID[i] & 0x0f); + work += objID[i + 1] & 0x40 ? (objID[i + 1] & 0xf) + 9 : objID[i + 1] & 0x0f; + object.push_back(work); + } + get->reset(OPAL_UID::OPAL_AUTHORITY_TABLE, OPAL_METHOD::EGET); + get->changeInvokingUid(object); + get->addToken(OPAL_TOKEN::STARTLIST); + get->addToken(OPAL_TOKEN::STARTLIST); + get->addToken(OPAL_TOKEN::ENDLIST); + get->addToken(OPAL_TOKEN::ENDLIST); + get->complete(); + LOG(I) << "Command:"; + get->dumpCommand(); + session = new DtaSession(this); + if (session->start((OPAL_UID)atoi(sp), pass, authority)) { + delete get; + delete session; + return 0xff; + } + if (session->sendCommand(get, response)) { + delete get; + delete session; + return 0xff; + } + LOG(I) << "Response:"; + get->dumpResponse(); + delete get; + delete session; + LOG(D1) << "Exiting DtaDevEnterprise::objDump"; + return 0; +} +#ifdef _MSC_VER +#pragma warning(pop) +#endif diff --git a/sedutil-master/Common/DtaDevEnterprise.h b/sedutil-master/Common/DtaDevEnterprise.h new file mode 100644 index 0000000..0453c48 --- /dev/null +++ b/sedutil-master/Common/DtaDevEnterprise.h @@ -0,0 +1,217 @@ +/* C:B************************************************************************** +This software is Copyright 2014-2017 Bright Plaza Inc. +This software is Copyright 2017 Spectra Logic Corporation + +This file is part of sedutil. + +sedutil is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +sedutil is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with sedutil. If not, see . + + * C:E********************************************************************** */ +#pragma once +class DtaCommand; +class DtaSession; + +#include "os.h" +#include "DtaOptions.h" +#include "DtaDev.h" +#include "DtaDevOS.h" +#include "DtaStructures.h" +#include "DtaLexicon.h" +#include "DtaResponse.h" // wouldn't take class +#include + +using namespace std; +/** Device Class represents a disk device, conforming to the TCG Enterprise standard +*/ + +class DtaDevEnterprise : public DtaDevOS { +public: + /** Constructor using an OS specific device descriptor. + * @param devref reference to device is OS specific lexicon + * */ + DtaDevEnterprise(const char * devref); + /** Default destructor, does nothing*/ + ~DtaDevEnterprise(); + /** Inform TPer of the communication propertied I wiah to use and + * receive the TPer maximum values + */ + uint8_t properties(); + /** Send a command to the device and wait for the response + * @param cmd the DtaCommand object containg the command + * @param response the DtaResonse object containing the response + * @param protocol The security protocol number to use for the command + */ + uint8_t exec(DtaCommand * cmd, DtaResponse & resp, uint8_t protocol = 0x01); + /** return the communications ID to be used for sessions to this device */ + uint16_t comID(); + /** Change the SID password from it's MSID default + * @param newpassword new password for SID + */ + uint8_t takeOwnership(char * newpassword); + /** Change the passwords for the enabled Bandmasters and the Erasemaster + * from the MSID default. + * @param defaultPassword the MSID password + * @param newPassword the nesw password to be set + * */ + uint8_t initLSPUsers(char * defaultPassword, char * newPassword); + /** retrieve the MSID password */ + uint8_t printDefaultPassword(); + /** retrieve a single row from a table + * @param table the UID of the table + * @param startcol the starting column of data requested + * @param endcol the ending column of the data requested + */ + uint8_t getTable(vector table, const char * startcol, + const char * endcol); + /** Set the SID password. + * Requires special handling because password is not always hashed. + * @param oldpassword current SID password + * @param newpassword value password is to be changed to + * @param hasholdpwd is the old password to be hashed before being added to the bytestream + * @param hashnewpwd is the new password to be hashed before being added to the bytestream + */ + uint8_t setSIDPassword(char * oldpassword, char * newpassword, + uint8_t hasholdpwd = 1, uint8_t hashnewpwd = 1); + /** set a single column in an object table + * @param table the UID of the table + * @param name the column name to be set + * @param value data to be stored the the column + */ + uint8_t setTable(vector table, const char *name, + vector value); + /** set a single column in a table + * @param table the UID of the table + * @param name the column name to be set + * @param value data to be stored the the column + */ + uint8_t setTable(vector table, const char *name, + OPAL_TOKEN value); + /** dummy code not implemented the the enterprise SSC */ + uint8_t activateLockingSP(char * password); + /** dummy code not implemented in teh enterprise SSC*/ + uint8_t activateLockingSP_SUM(uint8_t lockingrange, char * password); + /** dummy code not implemented in teh enterprise SSC*/ + uint8_t eraseLockingRange_SUM(uint8_t lockingrange, char * password); + /** dummy code not implemented in teh enterprise SSC*/ + uint8_t revertLockingSP(char * password, uint8_t keep = 0); + /** get the UID or CPIN ID of a user from their character name*/ + uint8_t getAuth4User(char * userid, uint8_t column, std::vector &userData); + /** Enable a Bandmaster Not functional */ + uint8_t enableUser(char * password, char * userid, OPAL_TOKEN status = OPAL_TOKEN::OPAL_TRUE); + /** Primitive to set the MBRDone flag. + * @param state 0 or 1 + * @param Admin1Password Locking SP authority with access to flag + */ + uint8_t setMBRDone(uint8_t state, char * Admin1Password); + /** Primitive to set the MBREnable flag. + * @param state 0 or 1 + * @param Admin1Password Locking SP authority with access to flag + */ + uint8_t setMBREnable(uint8_t state, char * Admin1Password); + + /** Set the password of a locking SP user. + * @param password current password + * @param userid the userid whose password is to be changed + * @param newpassword value password is to be changed to + */ + uint8_t setPassword(char * password, char * userid, char * newpassword); + /** dummy code not implemented in the enterprise SSC*/ + uint8_t setNewPassword_SUM(char * password, char * userid, char * newpassword); + uint8_t setLockingRange(uint8_t lockingrange, uint8_t lockingstate, + char * password); + /** dummy code not implemented in the enterprise SSC*/ + uint8_t setLockingRange_SUM(uint8_t lockingrange, uint8_t lockingstate, + char * password); + /** Setup a locking range. Initialize a locking range, set it's start + * LBA and length, initialize it as unlocked with locking disabled. + * @param lockingrange The Locking Range to be setup + * @param start Starting LBA + * @param length Number of blocks + * @param password Password of administrator + */ + uint8_t setupLockingRange(uint8_t lockingrange, uint64_t start, + uint64_t length, char * password); + /** dummy code not implemented in the enterprise SSC*/ + uint8_t setupLockingRange_SUM(uint8_t lockingrange, uint64_t start, + uint64_t length, char * password); + /** List status of locking ranges. + * @param password Password of administrator + */ + uint8_t listLockingRanges(char * password, int16_t rangeid); + /** Change the active state of a locking range + * @param lockingrange The number of the locking range (0 = global) + * @param enabled enable (true) or disable (false) the lockingrange + * @param password password of administrative authority for locking range + */ + uint8_t configureLockingRange(uint8_t lockingrange, uint8_t enabled, char * password); + /** Generate a new encryption key for a locking range. + * @param lockingrange locking range number + * @param password password of the locking administrative authority + */ + uint8_t rekeyLockingRange(uint8_t lockingrange, char * password); + uint8_t setBandsEnabled(int16_t lockingrange, char * password); + /** Reset the TPER to its factory condition + * ERASES ALL DATA! + * @param password password of authority (SID or PSID) + * @param PSID true or false is the authority the PSID + * */ + uint8_t revertTPer(char * password, uint8_t PSID = 0, uint8_t AdminSP = 0); + /** Erase a locking range + * @param lockingrange The number of the locking range (0 = global) + * @param password Password of administrative authority for locking range + */ + uint8_t eraseLockingRange(uint8_t lockingrange, char * password); + /** Loads a disk image file to the shadow MBR table. + * @param password the password for the administrative authority with access to the table + * @param filename the filename of the disk image + */ + uint8_t loadPBA(char * password, char * filename); + /** User command to prepare the device for management by sedutil. + * Specific to the SSC that the device supports + * @param password the password that is to be assigned to the SSC master entities + */ + uint8_t initialSetup(char * password); + /** dummy code not implemented in the enterprise SSC*/ + uint8_t setup_SUM(uint8_t lockingrange, uint64_t start, uint64_t length, char *Admin1Password, char * password); + /** Displays the identify and discovery 0 information */ + void puke(); + /** Dumps an object for diagnostic purposes + * @param sp index into the OPALUID table for the SP the object is in + * @param auth the authority ti use for the dump + * @param pass the password for the suthority + * @param objID the UID of the object to dump + * */ + uint8_t objDump(char *sp, char * auth, char *pass, char * objID); + /** Issue any command to the drive for diagnostic purposes + * @param sp index into the OPALUID table for the SP the object is in + * @param hexauth the authority ti use for the dump + * @param pass the password for the suthority + * @param hexinvokingUID caller of the method + * @param hexmethod the method to call + * @param hexparms the parameter list for the command + * + */ + uint8_t rawCmd(char *sp, char *hexauth, char *pass, + char *hexinvokingUID, char *hexmethod, char *hexparms); + + uint8_t readDataStore(char* filename, char* password); + + uint8_t writeDataStore(char* filename, char* password); + +protected: + uint8_t getDefaultPassword(); +private: + uint8_t getMaxRanges(char * password, uint16_t *maxRanges); + uint8_t getMaxRangesOpal(char * password, uint16_t *maxRanges); +}; diff --git a/sedutil-master/Common/DtaDevGeneric.cpp b/sedutil-master/Common/DtaDevGeneric.cpp new file mode 100644 index 0000000..ac44826 --- /dev/null +++ b/sedutil-master/Common/DtaDevGeneric.cpp @@ -0,0 +1,110 @@ +/* C:B************************************************************************** +This software is Copyright 2014-2017 Bright Plaza Inc. + +This file is part of sedutil. + +sedutil is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +sedutil is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with sedutil. If not, see . + + * C:E********************************************************************** */ +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4100) +#endif + +#include "os.h" +#include +#include +#include +#include +#include "DtaOptions.h" +#include "DtaDevGeneric.h" +#include "DtaHashPwd.h" +#include "DtaEndianFixup.h" +#include "DtaStructures.h" +#include "DtaCommand.h" +#include "DtaResponse.h" +#include "DtaSession.h" +#include "DtaHexDump.h" + +using namespace std; + +/** Class representing a disk device, this class is intended to be used when + * it is not yet known if the device is OPAL compliant + */ + +#define voidNOCODE(name, ...) void DtaDevGeneric::name(##__VA_ARGS__) { \ +LOG(E) << "Generic Device class does not support function " << #name << std::endl; \ +} +#define uint8NOCODE(name, ...) uint8_t DtaDevGeneric::name(__VA_ARGS__) { \ +LOG(E) << "Generic Device class does not support function " << #name << std::endl; \ +return 0xff; \ +} + +DtaDevGeneric::DtaDevGeneric(const char * devref) +{ + DtaDevOS::init(devref); +} + +DtaDevGeneric::~DtaDevGeneric() +{ +} +void DtaDevGeneric::init(const char * devref) +{ +} +uint8NOCODE(initialSetup, char *password) +uint8NOCODE(configureLockingRange,uint8_t lockingrange, + uint8_t enabled, char * password) +uint8NOCODE(revertLockingSP,char * password, uint8_t keep) +uint8NOCODE(setup_SUM, uint8_t lockingrange, uint64_t start, uint64_t length, char *Admin1Password, char * password) +uint8NOCODE(setPassword,char * password, char * userid, char * newpassword) +uint8NOCODE(setNewPassword_SUM,char * password, char * userid, char * newpassword) +uint8NOCODE(setMBREnable,uint8_t mbrstate, char * Admin1Password) +uint8NOCODE(setMBRDone,uint8_t mbrstate, char * Admin1Password) +uint8NOCODE(setLockingRange,uint8_t lockingrange, uint8_t lockingstate, + char * Admin1Password) +uint8NOCODE(setLockingRange_SUM, uint8_t lockingrange, uint8_t lockingstate, + char * password) +uint8NOCODE(setupLockingRange,uint8_t lockingrange, uint64_t start, + uint64_t length, char * password) +uint8NOCODE(listLockingRanges, char * password, int16_t rangeid) +uint8NOCODE(setupLockingRange_SUM, uint8_t lockingrange, uint64_t start, + uint64_t length, char * password) +uint8NOCODE(rekeyLockingRange, uint8_t lockingrange, char * password) +uint8NOCODE(setBandsEnabled, int16_t lockingrange, char * password) +uint8NOCODE(enableUser,char * password, char * userid, OPAL_TOKEN status) +uint8NOCODE(revertTPer,char * password, uint8_t PSID, uint8_t AdminSP) +uint8NOCODE(eraseLockingRange,uint8_t lockingrange, char * password) +uint8NOCODE(printDefaultPassword); +uint8NOCODE(loadPBA, char* password, char* filename) +uint8NOCODE(activateLockingSP, char* password) +uint8NOCODE(activateLockingSP_SUM, uint8_t lockingrange, char* password) +uint8NOCODE(eraseLockingRange_SUM, uint8_t lockingrange, char* password) +uint8NOCODE(takeOwnership, char* newpassword) +uint8NOCODE(setSIDPassword, char* oldpassword, char* newpassword, + uint8_t hasholdpwd, uint8_t hashnewpwd) + uint8NOCODE(readDataStore,char* filename, char* pass) + uint8NOCODE(writeDataStore, char* filename, char* password) + +uint16_t DtaDevGeneric::comID() +{ + LOG(E) << "Generic Device class does not support function " << "comID" << std::endl; + return 0xff; +} + +uint8NOCODE(exec,DtaCommand * cmd, DtaResponse & resp, uint8_t protocol) +uint8NOCODE(objDump,char *sp, char * auth, char *pass,char * objID) +uint8NOCODE(rawCmd,char *sp, char * auth, char *pass,char *invoker, char *method, char *plist) +#ifdef _MSC_VER +#pragma warning(pop) +#endif diff --git a/sedutil-master/Common/DtaDevGeneric.h b/sedutil-master/Common/DtaDevGeneric.h new file mode 100644 index 0000000..fabcb84 --- /dev/null +++ b/sedutil-master/Common/DtaDevGeneric.h @@ -0,0 +1,231 @@ +/* C:B************************************************************************** +This software is Copyright 2014-2017 Bright Plaza Inc. + +This file is part of sedutil. + +sedutil is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +sedutil is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with sedutil. If not, see . + + * C:E********************************************************************** */ +#pragma once +class DtaCommand; +class DtaSession; +#include "os.h" +#include "DtaDev.h" +#include "DtaDevOS.h" +#include "DtaStructures.h" + +#include + +using namespace std; +/** Device Class representing an unknown type of disk device. + * This device is used in determining if a disk supports a TCG Storage SSC. + * Most of the functions in this class are implemented to return an error as + * it is not known if the device supports a SSC + * +*/ +class DtaDevGeneric : public DtaDevOS { +public: + /** Constructor using an OS specific device descriptor. + * @param devref reference to device is OS specific lexicon + * */ + DtaDevGeneric(const char * devref); + /** Default constructor */ + ~DtaDevGeneric(); + /** OS specific initialization. + * This function should perform the necessary authority and environment checking + * to allow proper functioning of the program, open the device, perform an ATA + * identify, add the fields from the identify response to the disk info structure + * and if the device is an ATA device perform a call to Discovery0() to complete + * the disk_info structure + * @param devref character representation of the device is standard OS lexicon + */ + void init(const char * devref) ; + /* sedutil.cpp */ + /** User command to prepare the device for management by sedutil. + * Specific to the SSC that the device supports + * @param password the password that is to be assigned to the SSC master entities + */ + uint8_t initialSetup(char * password) ; + /** User command to prepare the drive for Single User Mode and rekey a SUM locking range. + * @param lockingrange locking range number to enable + * @param start LBA to start locking range + * @param length length (in blocks) for locking range + * @param Admin1Password admin1 password for TPer + * @param password User password to set for locking range + */ + uint8_t setup_SUM(uint8_t lockingrange, uint64_t start, uint64_t length, char *Admin1Password, char * password); + /** Set the SID password. + * Requires special handling because password is not always hashed. + * @param oldpassword current SID password + * @param newpassword value password is to be changed to + * @param hasholdpwd is the old password to be hashed before being added to the bytestream + * @param hashnewpwd is the new password to be hashed before being added to the bytestream + */ + uint8_t setSIDPassword(char * oldpassword, char * newpassword, + uint8_t hasholdpwd = 1, uint8_t hashnewpwd = 1) ; + /** Set the password of a locking SP user. + * @param password current password + * @param userid the userid whose password is to be changed + * @param newpassword value password is to be changed to + */ + uint8_t setPassword(char * password, char * userid, char * newpassword) ; + /** Set the password of a locking SP user in Single User Mode. + * @param password current user password + * @param userid the userid whose password is to be changed + * @param newpassword value password is to be changed to + */ + uint8_t setNewPassword_SUM(char * password, char * userid, char * newpassword) ; + /** Loads a disk image file to the shadow MBR table. + * @param password the password for the administrative authority with access to the table + * @param filename the filename of the disk image + */ + uint8_t loadPBA(char * password, char * filename) ; + /** Change the locking state of a locking range + * @param lockingrange The number of the locking range (0 = global) + * @param lockingstate the locking state to set + * @param Admin1Password password of administrative authority for locking range + */ + uint8_t setLockingRange(uint8_t lockingrange, uint8_t lockingstate, + char * Admin1Password) ; + /** Change the locking state of a locking range in Single User Mode + * @param lockingrange The number of the locking range (0 = global) + * @param lockingstate the locking state to set + * @param password password of user authority for the locking range + */ + uint8_t setLockingRange_SUM(uint8_t lockingrange, uint8_t lockingstate, + char * password); + /** Change the active state of a locking range + * @param lockingrange The number of the locking range (0 = global) + * @param enabled enable (true) or disable (false) the lockingrange + * @param password password of administrative authority for locking range + */ + uint8_t configureLockingRange(uint8_t lockingrange, uint8_t enabled, + char * password) ; + /** Setup a locking range. Initialize a locking range, set it's start + * LBA and length, initialize it as unlocked with locking disabled. + * @paran lockingrange The Locking Range to be setup + * @param start Starting LBA + * @param length Number of blocks + * @paran password Password of administrator + */ + uint8_t setupLockingRange(uint8_t lockingrange, uint64_t start, + uint64_t length, char * password); + /** Setup a locking range in Single User Mode. Initialize a locking range, + * set it's start LBA and length, initialize it as unlocked with locking enabled. + * @paran lockingrange The Locking Range to be setup + * @param start Starting LBA + * @param length Number of blocks + * @paran password Password of administrator + */ + uint8_t setupLockingRange_SUM(uint8_t lockingrange, uint64_t start, + uint64_t length, char * password); + /** Primitive to set the MBRDone flag. + * @param state 0 or 1 + * @param Admin1Password Locking SP authority with access to flag + */ + /** List status of locking ranges. + * @param password Password of administrator + */ + uint8_t listLockingRanges(char * password, int16_t rangeid); + /** Generate a new encryption key for a locking range. + * @param lockingrange locking range number + * @param password password of the locking administrative authority + */ + uint8_t rekeyLockingRange(uint8_t lockingrange, char * password); + /** Enable bands using MSID. + * @param lockingrange locking range number + */ + uint8_t setBandsEnabled(int16_t rangeid, char * password); + uint8_t setMBRDone(uint8_t state, char * Admin1Password) ; + /** Primitive to set the MBREnable flag. + * @param state 0 or 1 + * @param Admin1Password Locking SP authority with access to flag + */ + uint8_t setMBREnable(uint8_t state, char * Admin1Password) ; + /** enable a locking sp user. + * @param password password of locking sp administrative authority + * @param userid the user to be enabled + */ + uint8_t enableUser(char * password, char * userid, OPAL_TOKEN status = OPAL_TOKEN::OPAL_TRUE) ; + /** Enable locking on the device + * @param password password of the admin sp SID authority + */ + uint8_t activateLockingSP(char * password) ; + /** Enable locking on the device in Single User Mode + * @param lockingrange locking range to activate in SUM + * @param password password of the admin sp SID authority + */ + uint8_t activateLockingSP_SUM(uint8_t lockingrange, char * password); + /** Erase a Single User Mode locking range by calling the drive's erase method + * @param lockingrange The Locking Range to erase + * @param password The administrator password for the drive + */ + uint8_t eraseLockingRange_SUM(uint8_t lockingrange, char * password); + /** Change the SID password from it's MSID default + * @param newpassword new password for SID and locking SP admins + */ + uint8_t takeOwnership(char * newpassword) ; + /** Reset the Locking SP to its factory default condition + * ERASES ALL DATA! + * @param password of Administrative user + * @param keep true false for noerase function NOT WWORKING + */ + uint8_t revertLockingSP(char * password, uint8_t keep ) ; + /** Reset the TPER to its factory condition + * ERASES ALL DATA! + * @param password password of authority (SID or PSID) + * @param PSID true or false is the authority the PSID + * */ + uint8_t revertTPer(char * password, uint8_t PSID, uint8_t AdminSP ) ; + /** Erase a locking range + * @param lockingrange The number of the locking range (0 = global) + * @param password Password of administrative authority for locking range + */ + virtual uint8_t eraseLockingRange(uint8_t lockingrange, char * password); + /** Dumps an object for diagnostic purposes + * @param sp index into the OPALUID table for the SP the object is in + * @param auth the authority ti use for the dump + * @param pass the password for the suthority + * @param objID the UID of the object to dump + */ + uint8_t objDump(char *sp, char * auth, char *pass, + char * objID) ; + /** Issue any command to the drive for diagnostic purposes + * @param sp index into the OPALUID table for the SP the object is in + * @param auth the authority ti use for the dump + * @param pass the password for the suthority + * @param invoker caller of the method + * @param method the method to call + * @param plist the parameter list for the command + * + */ + uint8_t rawCmd(char *sp, char * auth, char *pass, + char *invoker, char *method, char *plist) ; + /** Read MSID + */ + uint8_t printDefaultPassword(); + /** Test the drive data store */ + uint8_t readDataStore(char* filename, char* pass); + + uint8_t writeDataStore(char* filename, char* password); + /* DtaSession.cpp */ + /** Send a command to the device and wait for the response + * @param cmd the MswdCommand object containg the command + * @param response the DtaResonse object containing the response + * @param protocol The security protocol number to use for the command + */ + uint8_t exec(DtaCommand * cmd, DtaResponse & resp, uint8_t protocol = 1) ; + /** return the communications ID to be used for sessions to this device */ + uint16_t comID() ; +}; diff --git a/sedutil-master/Common/DtaDevOpal.cpp b/sedutil-master/Common/DtaDevOpal.cpp new file mode 100644 index 0000000..94832a5 --- /dev/null +++ b/sedutil-master/Common/DtaDevOpal.cpp @@ -0,0 +1,2122 @@ +/* C:B************************************************************************** +This software is Copyright 2014-2017 Bright Plaza Inc. + +This file is part of sedutil. + +sedutil is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +sedutil is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with sedutil. If not, see . + + * C:E********************************************************************** */ +/** Device class for Opal 2.0 SSC + * also supports the Opal 1.0 SSC + */ +#include "os.h" +#include +#include +#include +#include +#include "DtaDevOpal.h" +#include "DtaHashPwd.h" +#include "DtaEndianFixup.h" +#include "DtaStructures.h" +#include "DtaCommand.h" +#include "DtaResponse.h" +#include "DtaSession.h" +#include "DtaHexDump.h" + +using namespace std; + +DtaDevOpal::DtaDevOpal() +{ +} + +DtaDevOpal::~DtaDevOpal() +{ +} +void DtaDevOpal::init(const char * devref) +{ + uint8_t lastRC; + DtaDevOS::init(devref); + if((lastRC = properties()) != 0) { LOG(E) << "Properties exchange failed";} +} + +uint8_t DtaDevOpal::initialSetup(char * password) +{ + LOG(D1) << "Entering initialSetup()"; + uint8_t lastRC; + if ((lastRC = takeOwnership(password)) != 0) { + LOG(E) << "Initial setup failed - unable to take ownership"; + return lastRC; + } + if ((lastRC = activateLockingSP(password)) != 0) { + LOG(E) << "Initial setup failed - unable to activate LockingSP"; + return lastRC; + } + if ((lastRC = configureLockingRange(0, DTA_DISABLELOCKING, password)) != 0) { + LOG(E) << "Initial setup failed - unable to configure global locking range"; + return lastRC; + } + if ((lastRC = setLockingRange(0, OPAL_LOCKINGSTATE::READWRITE, password)) != 0) { + LOG(E) << "Initial setup failed - unable to set global locking range RW"; + return lastRC; + } + if ((lastRC = setMBRDone(1, password)) != 0){ + LOG(E) << "Initial setup failed - unable to Enable MBR shadow"; + return lastRC; + } + if ((lastRC = setMBREnable(1, password)) != 0){ + LOG(E) << "Initial setup failed - unable to Enable MBR shadow"; + return lastRC; + } + + LOG(I) << "Initial setup of TPer complete on " << dev; + LOG(D1) << "Exiting initialSetup()"; + return 0; +} + +uint8_t DtaDevOpal::setup_SUM(uint8_t lockingrange, uint64_t start, uint64_t length, char *Admin1Password, char * password) +{ + LOG(D1) << "Entering setup_SUM()"; + uint8_t lastRC; + char defaultPW[] = ""; //OPAL defines the default initial User password as 0x00 + std::string userId; + userId.append("User"); + userId.append(std::to_string(lockingrange + 1)); //OPAL defines LR0 to User1, LR1 to User2, etc. + + //verify opal SUM support and status + if (!disk_info.Locking || !disk_info.SingleUser) + { + LOG(E) << "Setup_SUM failed - this drive does not support LockingSP / SUM"; + return DTAERROR_INVALID_COMMAND; + } + if (disk_info.Locking_lockingEnabled && !disk_info.SingleUser_any) + { + LOG(E) << "Setup_SUM failed - LockingSP has already been configured in standard mode."; + return DTAERROR_INVALID_COMMAND; + } + //If locking not enabled, run initial setup flow + if (!disk_info.Locking_lockingEnabled) + { + LOG(D1) << "LockingSP not enabled. Beginning initial setup flow."; + if ((lastRC = takeOwnership(Admin1Password)) != 0) { + LOG(E) << "Setup_SUM failed - unable to take ownership"; + return lastRC; + } + if ((lastRC = activateLockingSP_SUM(lockingrange, Admin1Password)) != 0) { + LOG(E) << "Setup_SUM failed - unable to activate LockingSP in SUM"; + return lastRC; + } + if ((lastRC = setupLockingRange_SUM(lockingrange, start, length, defaultPW)) != 0) { + LOG(E) << "Setup_SUM failed - unable to setup locking range " << lockingrange << "(" << start << "," << length << ")"; + return lastRC; + } + } + if ((lastRC = eraseLockingRange_SUM(lockingrange, Admin1Password)) != 0) { + LOG(E) << "Setup_SUM failed - unable to erase locking range"; + return lastRC; + } + + //verify that locking range covers correct LBAs + lrStatus_t lrStatus; + if ((lrStatus = getLockingRange_status(lockingrange, Admin1Password)).command_status != 0) { + LOG(E) << "Setup_SUM failed - unable to query locking range start/size"; + return lrStatus.command_status; + } + if (start != lrStatus.start || length != lrStatus.size) + { + LOG(D1) << "Incorrect Locking Range " << lockingrange << " start/size. Attempting to correct..."; + if ((lastRC = setupLockingRange_SUM(lockingrange, start, length, defaultPW)) != 0) { + LOG(E) << "Setup_SUM failed - unable to setup locking range " << lockingrange << "(" << start << "," << length << ")"; + return lastRC; + } + LOG(D1) << "Locking Range " << lockingrange << " start/size corrected."; + } + + //enable and set new password for locking range + if ((lastRC = setLockingRange_SUM(lockingrange, OPAL_LOCKINGSTATE::READWRITE, defaultPW)) != 0) { + LOG(E) << "Setup_SUM failed - unable to enable locking range"; + return lastRC; + } + if ((lastRC = setNewPassword_SUM(defaultPW, (char *)userId.c_str(), password)) != 0) { + LOG(E) << "Setup_SUM failed - unable to set new locking range password"; + return lastRC; + } + + LOG(I) << "Setup of SUM complete on " << dev; + LOG(D1) << "Exiting setup_SUM()"; + return 0; +} +DtaDevOpal::lrStatus_t DtaDevOpal::getLockingRange_status(uint8_t lockingrange, char * password) +{ + uint8_t lastRC; + lrStatus_t lrStatus; + LOG(D1) << "Entering DtaDevOpal:getLockingRange_status()"; + vector LR; + LR.push_back(OPAL_SHORT_ATOM::BYTESTRING8); + for (int i = 0; i < 8; i++) { + LR.push_back(OPALUID[OPAL_UID::OPAL_LOCKINGRANGE_GLOBAL][i]); + } + + session = new DtaSession(this); + if (NULL == session) { + LOG(E) << "Unable to create session object "; + lrStatus.command_status = DTAERROR_OBJECT_CREATE_FAILED; + return lrStatus; + } + if ((lastRC = session->start(OPAL_UID::OPAL_LOCKINGSP_UID, password, OPAL_UID::OPAL_ADMIN1_UID)) != 0) { + delete session; + lrStatus.command_status = lastRC; + return lrStatus; + } + if (0 != lockingrange) { + LR[8] = lockingrange & 0xff; + LR[6] = 0x03; // non global ranges are 00000802000300nn + } + if ((lastRC = getTable(LR, _OPAL_TOKEN::RANGESTART, _OPAL_TOKEN::WRITELOCKED)) != 0) { + delete session; + lrStatus.command_status = lastRC; + return lrStatus; + } + if (response.getTokenCount() < 24) + { + LOG(E) << "locking range getTable command did not return enough data"; + delete session; + lrStatus.command_status = DTAERROR_NO_LOCKING_INFO; + return lrStatus; + } + lrStatus.command_status = 0; + lrStatus.lockingrange_num = lockingrange; + lrStatus.start = response.getUint64(4); + lrStatus.size = response.getUint64(8); + lrStatus.RLKEna = (response.getUint8(12) != 0); + lrStatus.WLKEna = (response.getUint8(16) != 0); + lrStatus.RLocked = (response.getUint8(20) != 0); + lrStatus.WLocked = (response.getUint8(24) != 0); + LOG(D1) << "Locking Range " << lockingrange << " Begin: " << lrStatus.start << " Length: " + << lrStatus.size << " RLKEna: " << lrStatus.RLKEna << " WLKEna: " << lrStatus.WLKEna + << " RLocked: " << lrStatus.RLocked << " WLocked: " << lrStatus.WLocked; + delete session; + LOG(D1) << "Exiting DtaDevOpal:getLockingRange_status()"; + return lrStatus; +} +uint8_t DtaDevOpal::listLockingRanges(char * password, int16_t rangeid) +{ + uint8_t lastRC; + LOG(D1) << "Entering DtaDevOpal:listLockingRanges()" << rangeid; + vector LR; + LR.push_back(OPAL_SHORT_ATOM::BYTESTRING8); + for (int i = 0; i < 8; i++) { + LR.push_back(OPALUID[OPAL_UID::OPAL_LOCKINGRANGE_GLOBAL][i]); + } + + session = new DtaSession(this); + if (NULL == session) { + LOG(E) << "Unable to create session object "; + return DTAERROR_OBJECT_CREATE_FAILED; + } + if ((lastRC = session->start(OPAL_UID::OPAL_LOCKINGSP_UID, password, OPAL_UID::OPAL_ADMIN1_UID)) != 0) { + delete session; + return lastRC; + } + vector table; + table.push_back(OPAL_SHORT_ATOM::BYTESTRING8); + for (int i = 0; i < 8; i++) { + table.push_back(OPALUID[OPAL_UID::OPAL_LOCKING_INFO_TABLE][i]); + } + if ((lastRC = getTable(table, _OPAL_TOKEN::MAXRANGES, _OPAL_TOKEN::MAXRANGES)) != 0) { + delete session; + return lastRC; + } + if (response.tokenIs(4) != _OPAL_TOKEN::DTA_TOKENID_UINT) { + LOG(E) << "Unable to determine number of ranges "; + delete session; + return DTAERROR_NO_LOCKING_INFO; + } + LOG(I) << "Locking Range Configuration for " << dev; + uint32_t numRanges = response.getUint32(4) + 1; + for (uint32_t i = 0; i < numRanges; i++){ + if(0 != i) LR[8] = i & 0xff; + if ((lastRC = getTable(LR, _OPAL_TOKEN::RANGESTART, _OPAL_TOKEN::WRITELOCKED)) != 0) { + delete session; + return lastRC; + } + LR[6] = 0x03; // non global ranges are 00000802000300nn + LOG(I) << "LR" << i << " Begin " << response.getUint64(4) << + " for " << response.getUint64(8); + LOG(I) << " RLKEna =" << (response.getUint8(12) ? " Y " : " N ") << + " WLKEna =" << (response.getUint8(16) ? " Y " : " N ") << + " RLocked =" << (response.getUint8(20) ? " Y " : " N ") << + " WLocked =" << (response.getUint8(24) ? " Y " : " N "); + } + delete session; + LOG(D1) << "Exiting DtaDevOpal:listLockingRanges()"; + return 0; +} +uint8_t DtaDevOpal::setupLockingRange(uint8_t lockingrange, uint64_t start, + uint64_t length, char * password) +{ + uint8_t lastRC; + LOG(D1) << "Entering DtaDevOpal:setupLockingRange()"; + if (lockingrange < 1) { + LOG(E) << "global locking range cannot be changed"; + return DTAERROR_UNSUPORTED_LOCKING_RANGE; + } + vector LR; + LR.push_back(OPAL_SHORT_ATOM::BYTESTRING8); + for (int i = 0; i < 8; i++) { + LR.push_back(OPALUID[OPAL_UID::OPAL_LOCKINGRANGE_GLOBAL][i]); + } + LR[6] = 0x03; + LR[8] = lockingrange; + session = new DtaSession(this); + if (NULL == session) { + LOG(E) << "Unable to create session object "; + return DTAERROR_OBJECT_CREATE_FAILED; + } + if ((lastRC = session->start(OPAL_UID::OPAL_LOCKINGSP_UID, password, OPAL_UID::OPAL_ADMIN1_UID)) != 0) { + delete session; + return lastRC; + } + DtaCommand *set = new DtaCommand(); + if (NULL == set) { + LOG(E) << "Unable to create command object "; + delete session; + return DTAERROR_OBJECT_CREATE_FAILED; + } + set->reset(OPAL_UID::OPAL_AUTHORITY_TABLE, OPAL_METHOD::SET); + set->changeInvokingUid(LR); + set->addToken(OPAL_TOKEN::STARTLIST); + set->addToken(OPAL_TOKEN::STARTNAME); + set->addToken(OPAL_TOKEN::VALUES); + set->addToken(OPAL_TOKEN::STARTLIST); + set->addToken(OPAL_TOKEN::STARTNAME); + set->addToken(OPAL_TOKEN::RANGESTART); + set->addToken(start); + set->addToken(OPAL_TOKEN::ENDNAME); + set->addToken(OPAL_TOKEN::STARTNAME); + set->addToken(OPAL_TOKEN::RANGELENGTH); + set->addToken(length); + set->addToken(OPAL_TOKEN::ENDNAME); + set->addToken(OPAL_TOKEN::STARTNAME); + set->addToken(OPAL_TOKEN::READLOCKENABLED); + set->addToken(OPAL_TOKEN::OPAL_FALSE); + set->addToken(OPAL_TOKEN::ENDNAME); + set->addToken(OPAL_TOKEN::STARTNAME); + set->addToken(OPAL_TOKEN::WRITELOCKENABLED); + set->addToken(OPAL_TOKEN::OPAL_FALSE); + set->addToken(OPAL_TOKEN::ENDNAME); + set->addToken(OPAL_TOKEN::STARTNAME); + set->addToken(OPAL_TOKEN::READLOCKED); + set->addToken(OPAL_TOKEN::OPAL_FALSE); + set->addToken(OPAL_TOKEN::ENDNAME); + set->addToken(OPAL_TOKEN::STARTNAME); + set->addToken(OPAL_TOKEN::WRITELOCKED); + set->addToken(OPAL_TOKEN::OPAL_FALSE); + set->addToken(OPAL_TOKEN::ENDNAME); + set->addToken(OPAL_TOKEN::ENDLIST); + set->addToken(OPAL_TOKEN::ENDNAME); + set->addToken(OPAL_TOKEN::ENDLIST); + set->complete(); + if ((lastRC = session->sendCommand(set, response)) != 0) { + LOG(E) << "setupLockingRange Failed "; + delete set; + delete session; + return lastRC; + } + delete set; + delete session; + if ((lastRC = rekeyLockingRange(lockingrange, password)) != 0) { + LOG(E) << "setupLockingRange Unable to reKey Locking range -- Possible security issue "; + return lastRC; + } + LOG(I) << "LockingRange" << (uint16_t)lockingrange << " starting block " << start << + " for " << length << " blocks configured as unlocked range"; + LOG(D1) << "Exiting DtaDevOpal:setupLockingRange()"; + return 0; +} +uint8_t DtaDevOpal::setupLockingRange_SUM(uint8_t lockingrange, uint64_t start, + uint64_t length, char * password) +{ + uint8_t lastRC; + LOG(D1) << "Entering DtaDevOpal:setupLockingRange_SUM()"; + if (lockingrange < 1) { + LOG(E) << "global locking range cannot be changed"; + return DTAERROR_UNSUPORTED_LOCKING_RANGE; + } + vector LR; + LR.push_back(OPAL_SHORT_ATOM::BYTESTRING8); + for (int i = 0; i < 8; i++) { + LR.push_back(OPALUID[OPAL_UID::OPAL_LOCKINGRANGE_GLOBAL][i]); + } + LR[6] = 0x03; + LR[8] = lockingrange; + session = new DtaSession(this); + if (NULL == session) { + LOG(E) << "Unable to create session object "; + return DTAERROR_OBJECT_CREATE_FAILED; + } + vector auth; + auth.push_back(OPAL_SHORT_ATOM::BYTESTRING8); + for (int i = 0; i < 7; i++) { + auth.push_back(OPALUID[OPAL_UID::OPAL_USER1_UID][i]); + } + auth.push_back(lockingrange+1); + if ((lastRC = session->start(OPAL_UID::OPAL_LOCKINGSP_UID, password, auth)) != 0) { + LOG(E) << "Error starting session. Did you provide the correct user password? (GlobalRange = User1; Range1 = User2, etc.)"; + delete session; + return lastRC; + } + DtaCommand *set = new DtaCommand(); + if (NULL == set) { + LOG(E) << "Unable to create command object "; + delete session; + return DTAERROR_OBJECT_CREATE_FAILED; + } + set->reset(OPAL_UID::OPAL_AUTHORITY_TABLE, OPAL_METHOD::SET); + set->changeInvokingUid(LR); + set->addToken(OPAL_TOKEN::STARTLIST); + set->addToken(OPAL_TOKEN::STARTNAME); + set->addToken(OPAL_TOKEN::VALUES); + set->addToken(OPAL_TOKEN::STARTLIST); + set->addToken(OPAL_TOKEN::STARTNAME); + set->addToken(OPAL_TOKEN::RANGESTART); + set->addToken(start); + set->addToken(OPAL_TOKEN::ENDNAME); + set->addToken(OPAL_TOKEN::STARTNAME); + set->addToken(OPAL_TOKEN::RANGELENGTH); + set->addToken(length); + set->addToken(OPAL_TOKEN::ENDNAME); + set->addToken(OPAL_TOKEN::STARTNAME); + set->addToken(OPAL_TOKEN::READLOCKENABLED); + set->addToken(OPAL_TOKEN::OPAL_TRUE); + set->addToken(OPAL_TOKEN::ENDNAME); + set->addToken(OPAL_TOKEN::STARTNAME); + set->addToken(OPAL_TOKEN::WRITELOCKENABLED); + set->addToken(OPAL_TOKEN::OPAL_TRUE); + set->addToken(OPAL_TOKEN::ENDNAME); + set->addToken(OPAL_TOKEN::STARTNAME); + set->addToken(OPAL_TOKEN::READLOCKED); + set->addToken(OPAL_TOKEN::OPAL_FALSE); + set->addToken(OPAL_TOKEN::ENDNAME); + set->addToken(OPAL_TOKEN::STARTNAME); + set->addToken(OPAL_TOKEN::WRITELOCKED); + set->addToken(OPAL_TOKEN::OPAL_FALSE); + set->addToken(OPAL_TOKEN::ENDNAME); + set->addToken(OPAL_TOKEN::ENDLIST); + set->addToken(OPAL_TOKEN::ENDNAME); + set->addToken(OPAL_TOKEN::ENDLIST); + set->complete(); + if ((lastRC = session->sendCommand(set, response)) != 0) { + LOG(E) << "setupLockingRange Failed "; + delete set; + delete session; + return lastRC; + } + delete set; + delete session; + if ((lastRC = rekeyLockingRange_SUM(LR, auth, password)) != 0) { + LOG(E) << "setupLockingRange Unable to reKey Locking range -- Possible security issue "; + return lastRC; + } + LOG(I) << "LockingRange" << (uint16_t)lockingrange << " starting block " << start << + " for " << length << " blocks configured as LOCKED range"; + LOG(D1) << "Exiting DtaDevOpal:setupLockingRange_SUM()"; + return 0; +} +uint8_t DtaDevOpal::configureLockingRange(uint8_t lockingrange, uint8_t enabled, char * password) +{ + uint8_t lastRC; + LOG(D1) << "Entering DtaDevOpal::configureLockingRange()"; + vector LR; + LR.push_back(OPAL_SHORT_ATOM::BYTESTRING8); + for (int i = 0; i < 8; i++) { + LR.push_back(OPALUID[OPAL_UID::OPAL_LOCKINGRANGE_GLOBAL][i]); + } + if (lockingrange != 0) { + LR[6] = 0x03; + LR[8] = lockingrange; + } + session = new DtaSession(this); + if (NULL == session) { + LOG(E) << "Unable to create session object "; + return DTAERROR_OBJECT_CREATE_FAILED; + } + if ((lastRC = session->start(OPAL_UID::OPAL_LOCKINGSP_UID, password, OPAL_UID::OPAL_ADMIN1_UID)) != 0) { + delete session; + return lastRC; + } + DtaCommand *set = new DtaCommand(); + if (NULL == set) { + LOG(E) << "Unable to create command object "; + delete session; + return DTAERROR_OBJECT_CREATE_FAILED; + } + set->reset(OPAL_UID::OPAL_AUTHORITY_TABLE, OPAL_METHOD::SET); + set->changeInvokingUid(LR); + set->addToken(OPAL_TOKEN::STARTLIST); + set->addToken(OPAL_TOKEN::STARTNAME); + set->addToken(OPAL_TOKEN::VALUES); + set->addToken(OPAL_TOKEN::STARTLIST); + set->addToken(OPAL_TOKEN::STARTNAME); + set->addToken(OPAL_TOKEN::READLOCKENABLED); + set->addToken((enabled & DTA_READLOCKINGENABLED) ? OPAL_TRUE : OPAL_FALSE); + set->addToken(OPAL_TOKEN::ENDNAME); + set->addToken(OPAL_TOKEN::STARTNAME); + set->addToken(OPAL_TOKEN::WRITELOCKENABLED); + set->addToken((enabled & DTA_WRITELOCKINGENABLED) ? OPAL_TRUE : OPAL_FALSE); + set->addToken(OPAL_TOKEN::ENDNAME); + set->addToken(OPAL_TOKEN::ENDLIST); + set->addToken(OPAL_TOKEN::ENDNAME); + set->addToken(OPAL_TOKEN::ENDLIST); + set->complete(); + if ((lastRC = session->sendCommand(set, response)) != 0) { + LOG(E) << "configureLockingRange Failed "; + delete set; + delete session; + return lastRC; + } + delete set; + delete session; + LOG(I) << "LockingRange" << (uint16_t) lockingrange + << (enabled ? " enabled " : " disabled ") + << ((enabled & DTA_READLOCKINGENABLED) ? "ReadLocking" : "") + << ((enabled == (DTA_WRITELOCKINGENABLED | DTA_READLOCKINGENABLED)) ? "," : "") + << ((enabled & DTA_WRITELOCKINGENABLED) ? "WriteLocking" : ""); + LOG(D1) << "Exiting DtaDevOpal::configureLockingRange()"; + return 0; +} +uint8_t DtaDevOpal::rekeyLockingRange(uint8_t lockingrange, char * password) +{ + LOG(D1) << "Entering DtaDevOpal::rekeyLockingRange()"; + uint8_t lastRC; + vector LR; + LR.push_back(OPAL_SHORT_ATOM::BYTESTRING8); + for (int i = 0; i < 8; i++) { + LR.push_back(OPALUID[OPAL_UID::OPAL_LOCKINGRANGE_GLOBAL][i]); + } + if (lockingrange != 0) { + LR[6] = 0x03; + LR[8] = lockingrange; + } + session = new DtaSession(this); + if (NULL == session) { + LOG(E) << "Unable to create session object "; + return DTAERROR_OBJECT_CREATE_FAILED; + } + if ((lastRC = session->start(OPAL_UID::OPAL_LOCKINGSP_UID, password, OPAL_UID::OPAL_ADMIN1_UID)) != 0) { + delete session; + return lastRC; + } + if ((lastRC = getTable(LR, OPAL_TOKEN::ACTIVEKEY, OPAL_TOKEN::ACTIVEKEY)) != 0) { + delete session; + return lastRC; + } + DtaCommand *rekey = new DtaCommand(); + if (NULL == rekey) { + LOG(E) << "Unable to create command object "; + delete session; + return DTAERROR_OBJECT_CREATE_FAILED; + } + rekey->reset(OPAL_UID::OPAL_AUTHORITY_TABLE, OPAL_METHOD::GENKEY); + rekey->changeInvokingUid(response.getRawToken(4)); + rekey->addToken(OPAL_TOKEN::STARTLIST); + rekey->addToken(OPAL_TOKEN::ENDLIST); + rekey->complete(); + if ((lastRC = session->sendCommand(rekey, response)) != 0) { + LOG(E) << "rekeyLockingRange Failed "; + delete rekey; + delete session; + return lastRC; + } + delete rekey; + delete session; + LOG(I) << "LockingRange" << (uint16_t)lockingrange << " reKeyed "; + LOG(D1) << "Exiting DtaDevOpal::rekeyLockingRange()"; + return 0; +} +uint8_t DtaDevOpal::rekeyLockingRange_SUM(vector LR, vector UID, char * password) +{ + LOG(D1) << "Entering DtaDevOpal::rekeyLockingRange_SUM()"; + uint8_t lastRC; + + session = new DtaSession(this); + if (NULL == session) { + LOG(E) << "Unable to create session object "; + return DTAERROR_OBJECT_CREATE_FAILED; + } + if ((lastRC = session->start(OPAL_UID::OPAL_LOCKINGSP_UID, password, UID)) != 0) { + delete session; + return lastRC; + } + if ((lastRC = getTable(LR, OPAL_TOKEN::ACTIVEKEY, OPAL_TOKEN::ACTIVEKEY)) != 0) { + delete session; + return lastRC; + } + DtaCommand *rekey = new DtaCommand(); + if (NULL == rekey) { + LOG(E) << "Unable to create command object "; + delete session; + return DTAERROR_OBJECT_CREATE_FAILED; + } + rekey->reset(OPAL_UID::OPAL_AUTHORITY_TABLE, OPAL_METHOD::GENKEY); + rekey->changeInvokingUid(response.getRawToken(4)); + rekey->addToken(OPAL_TOKEN::STARTLIST); + rekey->addToken(OPAL_TOKEN::ENDLIST); + rekey->complete(); + if ((lastRC = session->sendCommand(rekey, response)) != 0) { + LOG(E) << "rekeyLockingRange_SUM Failed "; + delete rekey; + delete session; + return lastRC; + } + delete rekey; + delete session; + LOG(I) << "LockingRange reKeyed "; + LOG(D1) << "Exiting DtaDevOpal::rekeyLockingRange_SUM()"; + return 0; +} +uint8_t DtaDevOpal::setBandsEnabled(int16_t lockingrange, char * password) +{ + if (password == NULL) { LOG(D4) << "Password is NULL"; } // unreferenced formal paramater + LOG(D1) << "Entering DtaDevOpal::setBandsEnabled()" << lockingrange << " " << dev; + LOG(I) << "setBandsEnabled is not implemented. It is not part of the Opal SSC "; + LOG(D1) << "Exiting DtaDevOpal::setBandsEnabled()"; + return 0; +} +uint8_t DtaDevOpal::revertLockingSP(char * password, uint8_t keep) +{ + LOG(D1) << "Entering DtaDevOpal::revertLockingSP() keep = " << (uint16_t) keep; + uint8_t lastRC; + vector keepGlobalLocking; + keepGlobalLocking.push_back(0x83); + keepGlobalLocking.push_back(0x06); + keepGlobalLocking.push_back(0x00); + keepGlobalLocking.push_back(0x00); + DtaCommand *cmd = new DtaCommand(); + if (NULL == cmd) { + LOG(E) << "Create session object failed"; + return DTAERROR_OBJECT_CREATE_FAILED; + } + session = new DtaSession(this); + if (NULL == session) { + LOG(E) << "Create session object failed"; + delete cmd; + return DTAERROR_OBJECT_CREATE_FAILED; + } + if ((lastRC = session->start(OPAL_UID::OPAL_LOCKINGSP_UID, password, OPAL_UID::OPAL_ADMIN1_UID)) != 0) { + delete cmd; + delete session; + LOG(E) << "Start session failed"; + return lastRC; + } + cmd->reset(OPAL_UID::OPAL_THISSP_UID, OPAL_METHOD::REVERTSP); + cmd->addToken(OPAL_TOKEN::STARTLIST); + if (keep) { + cmd->addToken(OPAL_TOKEN::STARTNAME); + cmd->addToken(keepGlobalLocking); + cmd->addToken(OPAL_TOKEN::OPAL_TRUE); + cmd->addToken(OPAL_TOKEN::ENDNAME); + } + cmd->addToken(OPAL_TOKEN::ENDLIST); + cmd->complete(); + if ((lastRC = session->sendCommand(cmd, response)) != 0) { + LOG(E) << "Command failed"; + delete cmd; + delete session; + return lastRC; + } + // empty list returned so rely on method status + LOG(I) << "Revert LockingSP complete"; + session->expectAbort(); + delete session; + LOG(D1) << "Exiting DtaDevOpal::revertLockingSP()"; + return 0; +} +uint8_t DtaDevOpal::eraseLockingRange(uint8_t lockingrange, char * password) +{ + LOG(D1) << "Entering DtaDevOpal::eraseLockingRange()" << lockingrange << " " << dev; + if (password == NULL) { LOG(D4) << "Referencing formal parameters " << lockingrange; } + LOG(I) << "eraseLockingRange is not implemented. It is not part of the Opal SSC "; + LOG(D1) << "Exiting DtaDevOpal::eraseLockingRange()"; + return 0; +} +uint8_t DtaDevOpal::getAuth4User(char * userid, uint8_t uidorcpin, std::vector &userData) +{ + LOG(D1) << "Entering DtaDevOpal::getAuth4User()"; + userData.clear(); + userData. push_back(OPAL_SHORT_ATOM::BYTESTRING8); + userData.push_back(0x00); + userData.push_back(0x00); + userData.push_back(0x00); + if ((0 != uidorcpin) && (10 != uidorcpin)) { + LOG(E) << "Invalid Userid data requested" << (uint16_t)uidorcpin; + return DTAERROR_INVALID_PARAMETER; + } + if(uidorcpin) + userData.push_back(0x0b); + else + userData.push_back(0x09); + if (!memcmp("User", userid, 4)) { + userData.push_back(0x00); + userData.push_back(0x03); + userData.push_back(0x00); + userData.push_back(atoi(&userid[4]) &0xff ); + } + else { + if (!memcmp("Admin", userid, 5)) { + userData.push_back(0x00); + userData.push_back(0x01); + userData.push_back(0x00); + userData.push_back(atoi(&userid[5]) & 0xff ); + } + else { + LOG(E) << "Invalid Userid " << userid; + userData.clear(); + return DTAERROR_INVALID_PARAMETER; + } + } + LOG(D1) << "Exiting DtaDevOpal::getAuth4User()"; + return 0; +} +uint8_t DtaDevOpal::setPassword(char * password, char * userid, char * newpassword) +{ + LOG(D1) << "Entering DtaDevOpal::setPassword" ; + uint8_t lastRC; + std::vector userCPIN, hash; + session = new DtaSession(this); + if (NULL == session) { + LOG(E) << "Unable to create session object "; + return DTAERROR_OBJECT_CREATE_FAILED; + } + if ((lastRC = session->start(OPAL_UID::OPAL_LOCKINGSP_UID, password, OPAL_UID::OPAL_ADMIN1_UID)) != 0) { + delete session; + return lastRC; + } + if ((lastRC = getAuth4User(userid, 10, userCPIN)) != 0) { + LOG(E) << "Unable to find user " << userid << " in Authority Table"; + delete session; + return lastRC; + } + DtaHashPwd(hash, newpassword, this); + if ((lastRC = setTable(userCPIN, OPAL_TOKEN::PIN, hash)) != 0) { + LOG(E) << "Unable to set user " << userid << " new password "; + delete session; + return lastRC; + } + LOG(I) << userid << " password changed"; + delete session; + LOG(D1) << "Exiting DtaDevOpal::setPassword()"; + return 0; +} +uint8_t DtaDevOpal::setNewPassword_SUM(char * password, char * userid, char * newpassword) +{ + LOG(D1) << "Entering DtaDevOpal::setNewPassword_SUM"; + uint8_t lastRC; + std::vector userCPIN, hash; + session = new DtaSession(this); + if (NULL == session) { + LOG(E) << "Unable to create session object "; + return DTAERROR_OBJECT_CREATE_FAILED; + } + vector auth; + if (!memcmp("Admin", userid, 5)) + { + + auth.push_back(OPAL_SHORT_ATOM::BYTESTRING8); + for (int i = 0; i < 7; i++) { + auth.push_back(OPALUID[OPAL_UID::OPAL_ADMIN1_UID][i]); + } + auth.push_back((uint8_t)atoi(&userid[5])); + } + else if (!memcmp("User", userid, 4)) + { + auth.push_back(OPAL_SHORT_ATOM::BYTESTRING8); + for (int i = 0; i < 7; i++) { + auth.push_back(OPALUID[OPAL_UID::OPAL_USER1_UID][i]); + } + auth.push_back((uint8_t)atoi(&userid[4])); + } + else + { + LOG(E) << "Invalid userid \"" << userid << "\"specified for setNewPassword_SUM"; + delete session; + return DTAERROR_INVALID_PARAMETER; + } + if ((lastRC = session->start(OPAL_UID::OPAL_LOCKINGSP_UID, password, auth)) != 0) { + delete session; + return lastRC; + } + if ((lastRC = getAuth4User(userid, 10, userCPIN)) != 0) { + LOG(E) << "Unable to find user " << userid << " in Authority Table"; + delete session; + return lastRC; + } + DtaHashPwd(hash, newpassword, this); + if ((lastRC = setTable(userCPIN, OPAL_TOKEN::PIN, hash)) != 0) { + LOG(E) << "Unable to set user " << userid << " new password "; + delete session; + return lastRC; + } + LOG(I) << userid << " password changed"; + delete session; + LOG(D1) << "Exiting DtaDevOpal::setNewPassword_SUM()"; + return 0; +} +uint8_t DtaDevOpal::setMBREnable(uint8_t mbrstate, char * Admin1Password) +{ + LOG(D1) << "Entering DtaDevOpal::setMBREnable"; + uint8_t lastRC; + // set MBRDone before changing MBREnable so the PBA isn't presented + if ((lastRC = setMBRDone(1, Admin1Password)) != 0){ + LOG(E) << "unable to set MBRDone"; + return lastRC; + } + if (mbrstate) { + if ((lastRC = setLockingSPvalue(OPAL_UID::OPAL_MBRCONTROL, OPAL_TOKEN::MBRENABLE, + OPAL_TOKEN::OPAL_TRUE, Admin1Password, NULL)) != 0) { + LOG(E) << "Unable to set setMBREnable on"; + return lastRC; + } + else { + LOG(I) << "MBREnable set on "; + } + } + else { + if ((lastRC = setLockingSPvalue(OPAL_UID::OPAL_MBRCONTROL, OPAL_TOKEN::MBRENABLE, + OPAL_TOKEN::OPAL_FALSE, Admin1Password, NULL)) != 0) { + LOG(E) << "Unable to set setMBREnable off"; + return lastRC; + } + else { + LOG(I) << "MBREnable set off "; + } + } + LOG(D1) << "Exiting DtaDevOpal::setMBREnable"; + return 0; +} +uint8_t DtaDevOpal::setMBRDone(uint8_t mbrstate, char * Admin1Password) +{ + LOG(D1) << "Entering DtaDevOpal::setMBRDone"; + uint8_t lastRC; + if (mbrstate) { + if ((lastRC = setLockingSPvalue(OPAL_UID::OPAL_MBRCONTROL, OPAL_TOKEN::MBRDONE, + OPAL_TOKEN::OPAL_TRUE, Admin1Password, NULL)) != 0) { + LOG(E) << "Unable to set setMBRDone on"; + return lastRC; + } + else { + LOG(I) << "MBRDone set on "; + } + } + else { + if ((lastRC = setLockingSPvalue(OPAL_UID::OPAL_MBRCONTROL, OPAL_TOKEN::MBRDONE, + OPAL_TOKEN::OPAL_FALSE, Admin1Password, NULL)) != 0) { + LOG(E) << "Unable to set setMBRDone off"; + return lastRC; + } + else { + LOG(I) << "MBRDone set off "; + } + } + LOG(D1) << "Exiting DtaDevOpal::setMBRDone"; + return 0; +} +uint8_t DtaDevOpal::setLockingRange(uint8_t lockingrange, uint8_t lockingstate, + char * Admin1Password) +{ + uint8_t lastRC; + uint8_t archiveuser = 0; + OPAL_TOKEN readlocked, writelocked; + const char *msg; + + LOG(D1) << "Entering DtaDevOpal::setLockingRange"; + switch (lockingstate) { + case OPAL_LOCKINGSTATE::READWRITE: + readlocked = writelocked = OPAL_TOKEN::OPAL_FALSE; + msg = "RW"; + break; + case OPAL_LOCKINGSTATE::ARCHIVEUNLOCKED: + archiveuser = 1; + case OPAL_LOCKINGSTATE::READONLY: + readlocked = OPAL_TOKEN::OPAL_FALSE; + writelocked = OPAL_TOKEN::OPAL_TRUE; + msg = "RO"; + break; + case OPAL_LOCKINGSTATE::ARCHIVELOCKED: + archiveuser = 1; + case OPAL_LOCKINGSTATE::LOCKED: + readlocked = writelocked = OPAL_TOKEN::OPAL_TRUE; + msg = "LK"; + break; + default: + LOG(E) << "Invalid locking state for setLockingRange"; + return DTAERROR_INVALID_PARAMETER; + } + vector LR; + LR.push_back(OPAL_SHORT_ATOM::BYTESTRING8); + for (int i = 0; i < 8; i++) { + LR.push_back(OPALUID[OPAL_UID::OPAL_LOCKINGRANGE_GLOBAL][i]); + } + if (lockingrange != 0) { + LR[6] = 0x03; + LR[8] = lockingrange; + } + session = new DtaSession(this); + if (NULL == session) { + LOG(E) << "Unable to create session object "; + return DTAERROR_OBJECT_CREATE_FAILED; + } + if ((lastRC = session->start(OPAL_UID::OPAL_LOCKINGSP_UID, Admin1Password, OPAL_UID::OPAL_ADMIN1_UID)) != 0) { + delete session; + return lastRC; + } + DtaCommand *set = new DtaCommand(); + if (NULL == set) { + LOG(E) << "Unable to create command object "; + delete session; + return DTAERROR_OBJECT_CREATE_FAILED; + } + set->reset(OPAL_UID::OPAL_AUTHORITY_TABLE, OPAL_METHOD::SET); + set->changeInvokingUid(LR); + set->addToken(OPAL_TOKEN::STARTLIST); + set->addToken(OPAL_TOKEN::STARTNAME); + set->addToken(OPAL_TOKEN::VALUES); + set->addToken(OPAL_TOKEN::STARTLIST); + set->addToken(OPAL_TOKEN::STARTNAME); + set->addToken(OPAL_TOKEN::READLOCKED); + set->addToken(readlocked); + set->addToken(OPAL_TOKEN::ENDNAME); + if (!archiveuser) { + set->addToken(OPAL_TOKEN::STARTNAME); + set->addToken(OPAL_TOKEN::WRITELOCKED); + set->addToken(writelocked); + set->addToken(OPAL_TOKEN::ENDNAME); + } + set->addToken(OPAL_TOKEN::ENDLIST); + set->addToken(OPAL_TOKEN::ENDNAME); + set->addToken(OPAL_TOKEN::ENDLIST); + set->complete(); + if ((lastRC = session->sendCommand(set, response)) != 0) { + LOG(E) << "setLockingRange Failed "; + delete set; + delete session; + return lastRC; + } + delete set; + delete session; + LOG(I) << "LockingRange" << (uint16_t)lockingrange << " set to " << msg; + LOG(D1) << "Exiting DtaDevOpal::setLockingRange"; + return 0; +} +uint8_t DtaDevOpal::setLockingRange_SUM(uint8_t lockingrange, uint8_t lockingstate, + char * password) +{ + uint8_t lastRC; + OPAL_TOKEN readlocked, writelocked; + const char *msg; + + LOG(D1) << "Entering DtaDevOpal::setLockingRange_SUM"; + switch (lockingstate) { + case OPAL_LOCKINGSTATE::READWRITE: + readlocked = writelocked = OPAL_TOKEN::OPAL_FALSE; + msg = "RW"; + break; + case OPAL_LOCKINGSTATE::READONLY: + readlocked = OPAL_TOKEN::OPAL_FALSE; + writelocked = OPAL_TOKEN::OPAL_TRUE; + msg = "RO"; + break; + case OPAL_LOCKINGSTATE::LOCKED: + readlocked = writelocked = OPAL_TOKEN::OPAL_TRUE; + msg = "LK"; + break; + default: + LOG(E) << "Invalid locking state for setLockingRange"; + return DTAERROR_INVALID_PARAMETER; + } + vector LR; + LR.push_back(OPAL_SHORT_ATOM::BYTESTRING8); + for (int i = 0; i < 8; i++) { + LR.push_back(OPALUID[OPAL_UID::OPAL_LOCKINGRANGE_GLOBAL][i]); + } + if (lockingrange != 0) { + LR[6] = 0x03; + LR[8] = lockingrange; + } + session = new DtaSession(this); + if (NULL == session) { + LOG(E) << "Unable to create session object "; + return DTAERROR_OBJECT_CREATE_FAILED; + } + vector auth; + auth.push_back(OPAL_SHORT_ATOM::BYTESTRING8); + for (int i = 0; i < 7; i++) { + auth.push_back(OPALUID[OPAL_UID::OPAL_USER1_UID][i]); + } + auth.push_back(lockingrange+1); + if ((lastRC = session->start(OPAL_UID::OPAL_LOCKINGSP_UID, password, auth)) != 0) { + LOG(E) << "Error starting session. Did you provide the correct user password? (GlobalRange = User1; Range1 = User2, etc.)"; + delete session; + return lastRC; + } + + DtaCommand *set = new DtaCommand(); + if (NULL == set) { + LOG(E) << "Unable to create command object "; + delete session; + return DTAERROR_OBJECT_CREATE_FAILED; + } + set->reset(OPAL_UID::OPAL_AUTHORITY_TABLE, OPAL_METHOD::SET); + set->changeInvokingUid(LR); + set->addToken(OPAL_TOKEN::STARTLIST); + set->addToken(OPAL_TOKEN::STARTNAME); + set->addToken(OPAL_TOKEN::VALUES); + set->addToken(OPAL_TOKEN::STARTLIST); + + //enable locking on the range to enforce lock state + set->addToken(OPAL_TOKEN::STARTNAME); + set->addToken(OPAL_TOKEN::READLOCKENABLED); + set->addToken(OPAL_TOKEN::OPAL_TRUE); + set->addToken(OPAL_TOKEN::ENDNAME); + set->addToken(OPAL_TOKEN::STARTNAME); + set->addToken(OPAL_TOKEN::WRITELOCKENABLED); + set->addToken(OPAL_TOKEN::OPAL_TRUE); + set->addToken(OPAL_TOKEN::ENDNAME); + //set read/write locked + set->addToken(OPAL_TOKEN::STARTNAME); + set->addToken(OPAL_TOKEN::READLOCKED); + set->addToken(readlocked); + set->addToken(OPAL_TOKEN::ENDNAME); + set->addToken(OPAL_TOKEN::STARTNAME); + set->addToken(OPAL_TOKEN::WRITELOCKED); + set->addToken(writelocked); + set->addToken(OPAL_TOKEN::ENDNAME); + + set->addToken(OPAL_TOKEN::ENDLIST); + set->addToken(OPAL_TOKEN::ENDNAME); + set->addToken(OPAL_TOKEN::ENDLIST); + set->complete(); + if ((lastRC = session->sendCommand(set, response)) != 0) { + LOG(E) << "setLockingRange Failed "; + delete set; + delete session; + return lastRC; + } + delete set; + delete session; + LOG(I) << "LockingRange" << (uint16_t)lockingrange << " set to " << msg; + LOG(D1) << "Exiting DtaDevOpal::setLockingRange_SUM"; + return 0; +} +uint8_t DtaDevOpal::setLockingSPvalue(OPAL_UID table_uid, OPAL_TOKEN name, + OPAL_TOKEN value,char * password, char * msg) +{ + LOG(D1) << "Entering DtaDevOpal::setLockingSPvalue"; + uint8_t lastRC; + vector table; + table. push_back(OPAL_SHORT_ATOM::BYTESTRING8); + for (int i = 0; i < 8; i++) { + table.push_back(OPALUID[table_uid][i]); + } + session = new DtaSession(this); + if (NULL == session) { + LOG(E) << "Unable to create session object "; + return DTAERROR_OBJECT_CREATE_FAILED; + } + if ((lastRC = session->start(OPAL_UID::OPAL_LOCKINGSP_UID, password, OPAL_UID::OPAL_ADMIN1_UID)) != 0) { + delete session; + return lastRC; + } + if ((lastRC = setTable(table, name, value)) != 0) { + LOG(E) << "Unable to update table"; + delete session; + return lastRC; + } + if (NULL != msg) { + LOG(I) << msg; + } + + delete session; + LOG(D1) << "Exiting DtaDevOpal::setLockingSPvalue()"; + return 0; +} + +uint8_t DtaDevOpal::enableUser(char * password, char * userid, OPAL_TOKEN status) +{ + LOG(D1) << "Entering DtaDevOpal::enableUser"; + uint8_t lastRC; + vector userUID; + + session = new DtaSession(this); + if (NULL == session) { + LOG(E) << "Unable to create session object "; + return DTAERROR_OBJECT_CREATE_FAILED; + } + if ((lastRC = session->start(OPAL_UID::OPAL_LOCKINGSP_UID, password, OPAL_UID::OPAL_ADMIN1_UID)) != 0) { + delete session; + return lastRC; + } + if ((lastRC = getAuth4User(userid, 0, userUID)) != 0) { + LOG(E) << "Unable to find user " << userid << " in Authority Table"; + delete session; + return lastRC; + } + if ((lastRC = setTable(userUID, (OPAL_TOKEN)0x05, status)) != 0) { + LOG(E) << "Unable to enable user " << userid; + delete session; + return lastRC; + } + LOG(I) << userid << " has been enabled "; + delete session; + LOG(D1) << "Exiting DtaDevOpal::enableUser()"; + return 0; +} +uint8_t DtaDevOpal::revertTPer(char * password, uint8_t PSID, uint8_t AdminSP) +{ + LOG(D1) << "Entering DtaDevOpal::revertTPer() " << AdminSP; + uint8_t lastRC; + DtaCommand *cmd = new DtaCommand(); + if (NULL == cmd) { + LOG(E) << "Unable to create command object "; + return DTAERROR_OBJECT_CREATE_FAILED; + } + session = new DtaSession(this); + if (NULL == session) { + LOG(E) << "Unable to create session object "; + delete cmd; + return DTAERROR_OBJECT_CREATE_FAILED; + } + OPAL_UID uid = OPAL_UID::OPAL_SID_UID; + if (PSID) { + session->dontHashPwd(); // PSID pwd should be passed as entered + uid = OPAL_UID::OPAL_PSID_UID; + } + if ((lastRC = session->start(OPAL_UID::OPAL_ADMINSP_UID, password, uid)) != 0) { + delete cmd; + delete session; + return lastRC; + } + cmd->reset(OPAL_UID::OPAL_ADMINSP_UID, OPAL_METHOD::REVERT); + cmd->addToken(OPAL_TOKEN::STARTLIST); + cmd->addToken(OPAL_TOKEN::ENDLIST); + cmd->complete(); + session->expectAbort(); + if ((lastRC = session->sendCommand(cmd, response)) != 0) { + delete cmd; + delete session; + return lastRC; + } + LOG(I) << "revertTper completed successfully"; + delete cmd; + delete session; + LOG(D1) << "Exiting DtaDevOpal::revertTPer()"; + return 0; +} +uint8_t DtaDevOpal::loadPBA(char * password, char * filename) { + LOG(D1) << "Entering DtaDevOpal::loadPBAimage()" << filename << " " << dev; + uint8_t lastRC; + uint32_t blockSize; + uint32_t filepos = 0; + uint32_t eofpos; + ifstream pbafile; + (MAX_BUFFER_LENGTH > tperMaxPacket) ? blockSize = tperMaxPacket : blockSize = MAX_BUFFER_LENGTH; + if (blockSize > (tperMaxToken - 4)) blockSize = tperMaxToken - 4; + vector buffer, lengthtoken; + blockSize -= sizeof(OPALHeader) + 50; // packet overhead + buffer.resize(blockSize); + pbafile.open(filename, ios::in | ios::binary); + if (!pbafile) { + LOG(E) << "Unable to open PBA image file " << filename; + return DTAERROR_OPEN_ERR; + } + pbafile.seekg(0, pbafile.end); + eofpos = (uint32_t) pbafile.tellg(); + pbafile.seekg(0, pbafile.beg); + + DtaCommand *cmd = new DtaCommand(); + if (NULL == cmd) { + LOG(E) << "Unable to create command object "; + return DTAERROR_OBJECT_CREATE_FAILED; + } + + session = new DtaSession(this); + if (NULL == session) { + LOG(E) << "Unable to create session object "; + return DTAERROR_OBJECT_CREATE_FAILED; + } + if ((lastRC = session->start(OPAL_UID::OPAL_LOCKINGSP_UID, password, OPAL_UID::OPAL_ADMIN1_UID)) != 0) { + delete cmd; + delete session; + pbafile.close(); + return lastRC; + } + LOG(I) << "Writing PBA to " << dev; + + while (!pbafile.eof()) { + if (eofpos == filepos) break; + if ((eofpos - filepos) < blockSize) { + blockSize = eofpos - filepos; // handle a short last block + buffer.resize(blockSize); + } + lengthtoken.clear(); + lengthtoken.push_back(0xe2); + lengthtoken.push_back((uint8_t) ((blockSize >> 16) & 0x000000ff)); + lengthtoken.push_back((uint8_t)((blockSize >> 8) & 0x000000ff)); + lengthtoken.push_back((uint8_t)(blockSize & 0x000000ff)); + pbafile.read((char *)buffer.data(), blockSize); + cmd->reset(OPAL_UID::OPAL_MBR, OPAL_METHOD::SET); + cmd->addToken(OPAL_TOKEN::STARTLIST); + cmd->addToken(OPAL_TOKEN::STARTNAME); + cmd->addToken(OPAL_TOKEN::WHERE); + cmd->addToken(filepos); + cmd->addToken(OPAL_TOKEN::ENDNAME); + cmd->addToken(OPAL_TOKEN::STARTNAME); + cmd->addToken(OPAL_TOKEN::VALUES); + cmd->addToken(lengthtoken); + cmd->addToken(buffer); + cmd->addToken(OPAL_TOKEN::ENDNAME); + cmd->addToken(OPAL_TOKEN::ENDLIST); + cmd->complete(); + if ((lastRC = session->sendCommand(cmd, response)) != 0) { + delete cmd; + delete session; + pbafile.close(); + return lastRC; + } + filepos += blockSize; + cout << filepos << " of " << eofpos << " " << (uint16_t) (((float)filepos/(float)eofpos) * 100) << "% blk=" << blockSize << " \r"; + } + cout << "\n"; + delete cmd; + delete session; + pbafile.close(); + LOG(I) << "PBA image " << filename << " written to " << dev; + LOG(D1) << "Exiting DtaDevOpal::loadPBAimage()"; + return 0; +} + +uint8_t DtaDevOpal::activateLockingSP(char * password) +{ + LOG(D1) << "Entering DtaDevOpal::activateLockingSP()"; + uint8_t lastRC; + vector table; + table. push_back(OPAL_SHORT_ATOM::BYTESTRING8); + for (int i = 0; i < 8; i++) { + table.push_back(OPALUID[OPAL_UID::OPAL_LOCKINGSP_UID][i]); + } + DtaCommand *cmd = new DtaCommand(); + if (NULL == cmd) { + LOG(E) << "Unable to create command object "; + return DTAERROR_OBJECT_CREATE_FAILED; + } + session = new DtaSession(this); + if (NULL == session) { + LOG(E) << "Unable to create session object "; + return DTAERROR_OBJECT_CREATE_FAILED; + } + if ((lastRC = session->start(OPAL_UID::OPAL_ADMINSP_UID, password, OPAL_UID::OPAL_SID_UID)) != 0) { + delete cmd; + delete session; + return lastRC; + } + if ((lastRC = getTable(table, 0x06, 0x06)) != 0) { + LOG(E) << "Unable to determine LockingSP Lifecycle state"; + delete cmd; + delete session; + return lastRC; + } + if ((0x06 != response.getUint8(3)) || // getlifecycle + (0x08 != response.getUint8(4))) // Manufactured-Inactive + { + LOG(E) << "Locking SP lifecycle is not Manufactured-Inactive"; + delete cmd; + delete session; + return DTAERROR_INVALID_LIFECYCLE; + } + cmd->reset(OPAL_UID::OPAL_LOCKINGSP_UID, OPAL_METHOD::ACTIVATE); + cmd->addToken(OPAL_TOKEN::STARTLIST); + cmd->addToken(OPAL_TOKEN::ENDLIST); + cmd->complete(); + if ((lastRC = session->sendCommand(cmd, response)) != 0) { + delete cmd; + delete session; + return lastRC; + } + LOG(I) << "Locking SP Activate Complete"; + + delete cmd; + delete session; + LOG(D1) << "Exiting DtaDevOpal::activatLockingSP()"; + return 0; +} + +uint8_t DtaDevOpal::activateLockingSP_SUM(uint8_t lockingrange, char * password) +{ + LOG(D1) << "Entering DtaDevOpal::activateLockingSP_SUM()"; + uint8_t lastRC; + vector table; + table.push_back(OPAL_SHORT_ATOM::BYTESTRING8); + for (int i = 0; i < 8; i++) { + table.push_back(OPALUID[OPAL_UID::OPAL_LOCKINGSP_UID][i]); + } + vector LR; + LR.push_back(OPAL_SHORT_ATOM::BYTESTRING8); + for (int i = 0; i < 8; i++) { + LR.push_back(OPALUID[OPAL_UID::OPAL_LOCKINGRANGE_GLOBAL][i]); + } + if (lockingrange > 0) { + LR[6] = 0x03; + LR[8] = lockingrange; + } + DtaCommand *cmd = new DtaCommand(); + if (NULL == cmd) { + LOG(E) << "Unable to create command object "; + return DTAERROR_OBJECT_CREATE_FAILED; + } + session = new DtaSession(this); + if (NULL == session) { + LOG(E) << "Unable to create session object "; + return DTAERROR_OBJECT_CREATE_FAILED; + } + if ((lastRC = session->start(OPAL_UID::OPAL_ADMINSP_UID, password, OPAL_UID::OPAL_SID_UID)) != 0) { + LOG(E) << "session->start failed with code " << lastRC; + delete cmd; + delete session; + return lastRC; + } + if ((lastRC = getTable(table, 0x06, 0x06)) != 0) { + LOG(E) << "Unable to determine LockingSP Lifecycle state"; + delete cmd; + delete session; + return lastRC; + } + if ((0x06 != response.getUint8(3)) || // getlifecycle + (0x08 != response.getUint8(4))) // Manufactured-Inactive + { + LOG(E) << "Locking SP lifecycle is not Manufactured-Inactive"; + delete cmd; + delete session; + return DTAERROR_INVALID_LIFECYCLE; + } + /*if (!disk_info.SingleUser) + { + LOG(E) << "This Locking SP does not support Single User Mode"; + delete cmd; + delete session; + return DTAERROR_INVALID_COMMAND; + }*/ + cmd->reset(OPAL_UID::OPAL_LOCKINGSP_UID, OPAL_METHOD::ACTIVATE); + cmd->addToken(OPAL_TOKEN::STARTLIST); + cmd->addToken(OPAL_TOKEN::STARTNAME); + //SingleUserModeSelectionList parameter + cmd->addToken(OPAL_SHORT_ATOM::UINT_3); + cmd->addToken(OPAL_TINY_ATOM::UINT_06); + cmd->addToken(OPAL_TINY_ATOM::UINT_00); + cmd->addToken(OPAL_TINY_ATOM::UINT_00); + cmd->addToken(OPAL_TOKEN::STARTLIST); + cmd->addToken(LR); + cmd->addToken(OPAL_TOKEN::ENDLIST); + cmd->addToken(OPAL_TOKEN::ENDNAME); + cmd->addToken(OPAL_TOKEN::ENDLIST); + cmd->complete(); + if ((lastRC = session->sendCommand(cmd, response)) != 0) { + LOG(E) << "session->sendCommand failed with code " << lastRC; + delete cmd; + delete session; + return lastRC; + } + disk_info.Locking_lockingEnabled = 1; + LOG(I) << "Locking SP Activate Complete for single User" << (lockingrange+1) << " on locking range " << (int)lockingrange; + + delete cmd; + delete session; + LOG(D1) << "Exiting DtaDevOpal::activateLockingSP_SUM()"; + return 0; +} + +uint8_t DtaDevOpal::eraseLockingRange_SUM(uint8_t lockingrange, char * password) +{ + uint8_t lastRC; + LOG(D1) << "Entering DtaDevOpal::eraseLockingRange_SUM"; + vector LR; + LR.push_back(OPAL_SHORT_ATOM::BYTESTRING8); + for (int i = 0; i < 8; i++) { + LR.push_back(OPALUID[OPAL_UID::OPAL_LOCKINGRANGE_GLOBAL][i]); + } + if (lockingrange != 0) { + LR[6] = 0x03; + LR[8] = lockingrange; + } + session = new DtaSession(this); + if (NULL == session) { + LOG(E) << "Unable to create session object "; + return DTAERROR_OBJECT_CREATE_FAILED; + } + if ((lastRC = session->start(OPAL_UID::OPAL_LOCKINGSP_UID, password, OPAL_UID::OPAL_ADMIN1_UID)) != 0) { + delete session; + return lastRC; + } + + DtaCommand *cmd = new DtaCommand(); + if (NULL == cmd) { + LOG(E) << "Unable to create command object "; + delete session; + return DTAERROR_OBJECT_CREATE_FAILED; + } + cmd->reset(OPAL_UID::OPAL_AUTHORITY_TABLE, OPAL_METHOD::ERASE); + cmd->changeInvokingUid(LR); + cmd->addToken(OPAL_TOKEN::STARTLIST); + cmd->addToken(OPAL_TOKEN::ENDLIST); + cmd->complete(); + if ((lastRC = session->sendCommand(cmd, response)) != 0) { + LOG(E) << "setLockingRange Failed "; + delete cmd; + delete session; + return lastRC; + } + delete cmd; + delete session; + LOG(I) << "LockingRange" << (uint16_t)lockingrange << " erased"; + LOG(D1) << "Exiting DtaDevOpal::eraseLockingRange_SUM"; + return 0; +} + +uint8_t DtaDevOpal::takeOwnership(char * newpassword) +{ + LOG(D1) << "Entering DtaDevOpal::takeOwnership()"; + uint8_t lastRC; + if ((lastRC = getDefaultPassword()) != 0) { + LOG(E) << "Unable to read MSID password "; + return lastRC; + } + if ((lastRC = setSIDPassword((char *)response.getString(4).c_str(), newpassword, 0)) != 0) { + LOG(E) << "takeOwnership failed"; + return lastRC; + } + LOG(I) << "takeOwnership complete"; + LOG(D1) << "Exiting takeOwnership()"; + return 0; +} +uint8_t DtaDevOpal::getDefaultPassword() +{ + LOG(D1) << "Entering DtaDevOpal::getDefaultPassword()"; + uint8_t lastRC; + vector hash; + session = new DtaSession(this); + if (NULL == session) { + LOG(E) << "Unable to create session object "; + return DTAERROR_OBJECT_CREATE_FAILED; + } + if ((lastRC = session->start(OPAL_UID::OPAL_ADMINSP_UID)) != 0) { + LOG(E) << "Unable to start Unauthenticated session " << dev; + delete session; + return lastRC; + } + vector table; + table. push_back(OPAL_SHORT_ATOM::BYTESTRING8); + for (int i = 0; i < 8; i++) { + table.push_back(OPALUID[OPAL_UID::OPAL_C_PIN_MSID][i]); + } + if ((lastRC = getTable(table, PIN, PIN)) != 0) { + delete session; + return lastRC; + } + delete session; + LOG(D1) << "Exiting getDefaultPassword()"; + return 0; +} +uint8_t DtaDevOpal::printDefaultPassword() +{ + const uint8_t rc = getDefaultPassword(); + if (rc) { + LOG(E) << "unable to read MSID password"; + return rc; + } + string defaultPassword = response.getString(4); + fprintf(stdout, "MSID: %s\n", (char *)defaultPassword.c_str()); + return 0; +} + +uint8_t DtaDevOpal::writeDataStore(char* filename, char* password) +{ + + uint8_t lastRC; + uint32_t blockSize; + uint32_t filepos = 0; + uint32_t eofpos; + uint32_t size = 0; + uint32_t sizeSize = 4;//4 bytes for the size of the size; + + ifstream inputfile; + + printf("Writing %s to DataStore\n", filename); + + (MAX_BUFFER_LENGTH > tperMaxPacket) ? blockSize = tperMaxPacket : blockSize = MAX_BUFFER_LENGTH; + if (blockSize > (tperMaxToken - 4)) blockSize = tperMaxToken - 4; + vector buffer, lengthtoken, sizetoken; + blockSize -= sizeof(OPALHeader) + 50; // packet overhead + buffer.resize(blockSize); + inputfile.open(filename, ios::in | ios::binary); + if (!inputfile) { + printf("Unable to open file %s",filename); + return DTAERROR_OPEN_ERR; + } + inputfile.seekg(0, inputfile.end); + eofpos = (uint32_t)inputfile.tellg(); + inputfile.seekg(0, inputfile.beg); + + size = eofpos; + + DtaCommand* cmd = new DtaCommand(); + if (NULL == cmd) { + printf("Unable to create command object "); + return DTAERROR_OBJECT_CREATE_FAILED; + } + + session = new DtaSession(this); + if (NULL == session) { + printf("Unable to create session object "); + return DTAERROR_OBJECT_CREATE_FAILED; + } + if ((lastRC = session->start(OPAL_UID::OPAL_LOCKINGSP_UID, password, OPAL_UID::OPAL_ADMIN1_UID)) != 0) { + delete cmd; + delete session; + inputfile.close(); + return lastRC; + } + + lengthtoken.clear(); + lengthtoken.push_back(0xe2); + lengthtoken.push_back((uint8_t)((sizeSize >> 16) & 0x000000ff)); + lengthtoken.push_back((uint8_t)((sizeSize >> 8) & 0x000000ff)); + lengthtoken.push_back((uint8_t)(sizeSize & 0x000000ff)); + + sizetoken.clear(); + sizetoken.push_back((uint8_t)((size >> 24) & 0x000000ff)); + sizetoken.push_back((uint8_t)((size >> 16) & 0x000000ff)); + sizetoken.push_back((uint8_t)((size >> 8) & 0x000000ff)); + sizetoken.push_back((uint8_t)(size & 0x000000ff)); + + cmd->reset(OPAL_UID::OPAL_UID_DATASTORE, OPAL_METHOD::SET); + cmd->addToken(OPAL_TOKEN::STARTLIST); + cmd->addToken(OPAL_TOKEN::STARTNAME); + cmd->addToken(OPAL_TOKEN::WHERE); + cmd->addToken(filepos); + cmd->addToken(OPAL_TOKEN::ENDNAME); + cmd->addToken(OPAL_TOKEN::STARTNAME); + cmd->addToken(OPAL_TOKEN::VALUES); + cmd->addToken(lengthtoken); + cmd->addToken(sizetoken); + cmd->addToken(OPAL_TOKEN::ENDNAME); + cmd->addToken(OPAL_TOKEN::ENDLIST); + cmd->complete(); + if ((lastRC = session->sendCommand(cmd, response)) != 0) { + delete cmd; + delete session; + inputfile.close(); + return lastRC; + } + + filepos += 4; //+4 for the size record + eofpos += 4; //+4 to compensate for size record. + while (!inputfile.eof()) { + if (eofpos == filepos) break; + if ((eofpos - filepos) < blockSize) { + blockSize = eofpos - filepos; // handle a short last block + buffer.resize(blockSize); + } + lengthtoken.clear(); + lengthtoken.push_back(0xe2); + lengthtoken.push_back((uint8_t)((blockSize >> 16) & 0x000000ff)); + lengthtoken.push_back((uint8_t)((blockSize >> 8) & 0x000000ff)); + lengthtoken.push_back((uint8_t)(blockSize & 0x000000ff)); + + inputfile.read((char*)buffer.data(), blockSize); + cmd->reset(OPAL_UID::OPAL_UID_DATASTORE, OPAL_METHOD::SET); + cmd->addToken(OPAL_TOKEN::STARTLIST); + cmd->addToken(OPAL_TOKEN::STARTNAME); + cmd->addToken(OPAL_TOKEN::WHERE); + cmd->addToken(filepos); + cmd->addToken(OPAL_TOKEN::ENDNAME); + cmd->addToken(OPAL_TOKEN::STARTNAME); + cmd->addToken(OPAL_TOKEN::VALUES); + cmd->addToken(lengthtoken); + cmd->addToken(buffer); + cmd->addToken(OPAL_TOKEN::ENDNAME); + cmd->addToken(OPAL_TOKEN::ENDLIST); + cmd->complete(); + if ((lastRC = session->sendCommand(cmd, response)) != 0) { + delete cmd; + delete session; + inputfile.close(); + return lastRC; + } + filepos += blockSize; + //cout << filepos << " of " << eofpos << " " << (uint16_t)(((float)filepos / (float)eofpos) * 100) << "% blk=" << blockSize << " \r"; + } + //cout << "\n"; + delete cmd; + delete session; + inputfile.close(); + printf("%d bytes written to DataStore\n",size); + LOG(D1) << "Exiting DtaDevOpal::testDataStore()"; + return 0; +} +uint8_t DtaDevOpal::readDataStore(char* outputfile, char* password) +{ + vector table; + uint8_t lastRC; + uint32_t size = 0; + uint8_t* contentBytes = 0; + uint32_t blockSize = 1792; + uint32_t contentSize = blockSize; + uint32_t readBytes = 0; + uint32_t firstrow = 0; + uint32_t secondrow = 0; + //uint32_t nextreadsize = 0; + uint8_t sizeBytes[4] = { 0 }; + ofstream outstream; + + + + printf("Reading file from DataStore\n"); + + session = new DtaSession(this); + if (NULL == session) { + printf("Unable to create session object\n"); + return DTAERROR_OBJECT_CREATE_FAILED; + } + + if ((lastRC = session->start(OPAL_UID::OPAL_LOCKINGSP_UID, + password, OPAL_UID::OPAL_ADMIN1_UID)) != 0) { + printf("Unable to start session\n"); + delete session; + return lastRC; + } + + table.clear(); + table.push_back(OPAL_SHORT_ATOM::BYTESTRING8); + for (int i = 0; i < 8; i++) { + table.push_back(OPALUID[OPAL_UID::OPAL_UID_DATASTORE][i]); + } + + + if ((lastRC = getTableDataStore(table, 0x00, 0x03)) != 0) { + printf("unable to get datastore table\n"); + delete session; + return lastRC; + } + + + + response.getBytes(1,sizeBytes); + + size = uint32_t((unsigned char)(sizeBytes[0]) << 24 | + (unsigned char)(sizeBytes[1]) << 16 | + (unsigned char)(sizeBytes[2]) << 8 | + (unsigned char)(sizeBytes[3])); + + //printf("size is %d\n", size); + contentBytes = new uint8_t[blockSize]; + if (NULL == contentBytes) + { + printf("failed to instantiate datastore content array\n"); + delete session; + return DTAERROR_OBJECT_CREATE_FAILED; + } + + //printf("after allocation"); + + firstrow = 4; //after the size bytes + + + + outstream.open(outputfile, ios::out | ios::binary); + + //if the blockSize is greater than the size of the file just grab the whole file size in one go. + if (size < blockSize) + { + secondrow = size + 3; //+4 for size bytes -1 for 0 index + blockSize = size; + } + else + { + secondrow = blockSize + 3; + } + + + while (readBytes < size) + { + + if (readBytes == size) + { + break; + } + + //printf("reading firstrow %d secondrow %d\n", firstrow, secondrow); + + if ((lastRC = getTableDataStore(table, firstrow, secondrow)) != 0) { + printf("unable to get datastore table\n"); + delete session; + delete[] contentBytes; + outstream.close(); + return lastRC; + } + + memset(contentBytes, 0, contentSize); + response.getBytes(1, contentBytes); + + + outstream.write((const char*)contentBytes, (blockSize)); + + readBytes += blockSize; + + if ((size - readBytes) < blockSize) + { + blockSize = size - readBytes; // handle a short last block + //printf("blocksize is now %d", blockSize); + } + + + firstrow = secondrow+1; + secondrow += blockSize; + } + printf("Read %d bytes to %s from DataStore",readBytes, outputfile); + //printf("\n"); + outstream.close(); + delete[] contentBytes; + delete session; + return 0; +} + +uint8_t DtaDevOpal::setSIDPassword(char * oldpassword, char * newpassword, + uint8_t hasholdpwd, uint8_t hashnewpwd) +{ + vector hash, table; + LOG(D1) << "Entering DtaDevOpal::setSIDPassword()"; + uint8_t lastRC; + session = new DtaSession(this); + if (NULL == session) { + LOG(E) << "Unable to create session object "; + return DTAERROR_OBJECT_CREATE_FAILED; + } + if (!hasholdpwd) session->dontHashPwd(); + if ((lastRC = session->start(OPAL_UID::OPAL_ADMINSP_UID, + oldpassword, OPAL_UID::OPAL_SID_UID)) != 0) { + delete session; + return lastRC; + } + table.clear(); + table. push_back(OPAL_SHORT_ATOM::BYTESTRING8); + for (int i = 0; i < 8; i++) { + table.push_back(OPALUID[OPAL_UID::OPAL_C_PIN_SID][i]); + } + hash.clear(); + if (hashnewpwd) { + DtaHashPwd(hash, newpassword, this); + } + else { + hash.push_back(0xd0); + hash.push_back((uint8_t)strnlen(newpassword, 255)); + for (uint16_t i = 0; i < strnlen(newpassword, 255); i++) { + hash.push_back(newpassword[i]); + } + } + if ((lastRC = setTable(table, OPAL_TOKEN::PIN, hash)) != 0) { + LOG(E) << "Unable to set new SID password "; + delete session; + return lastRC; + } + delete session; + LOG(D1) << "Exiting DtaDevOpal::setSIDPassword()"; + return 0; +} + +uint8_t DtaDevOpal::setTable(vector table, OPAL_TOKEN name, + OPAL_TOKEN value) +{ + vector token; + token.push_back((uint8_t) value); + return(setTable(table, name, token)); +} + +uint8_t DtaDevOpal::setTable(vector table, OPAL_TOKEN name, + vector value) +{ + LOG(D1) << "Entering DtaDevOpal::setTable"; + uint8_t lastRC; + DtaCommand *set = new DtaCommand(); + if (NULL == set) { + LOG(E) << "Unable to create command object "; + return DTAERROR_OBJECT_CREATE_FAILED; + } + set->reset(OPAL_UID::OPAL_AUTHORITY_TABLE, OPAL_METHOD::SET); + set->changeInvokingUid(table); + set->addToken(OPAL_TOKEN::STARTLIST); + set->addToken(OPAL_TOKEN::STARTNAME); + set->addToken(OPAL_TOKEN::VALUES); // "values" + set->addToken(OPAL_TOKEN::STARTLIST); + set->addToken(OPAL_TOKEN::STARTNAME); + set->addToken(name); + set->addToken(value); + set->addToken(OPAL_TOKEN::ENDNAME); + set->addToken(OPAL_TOKEN::ENDLIST); + set->addToken(OPAL_TOKEN::ENDNAME); + set->addToken(OPAL_TOKEN::ENDLIST); + set->complete(); + if ((lastRC = session->sendCommand(set, response)) != 0) { + LOG(E) << "Set Failed "; + delete set; + return lastRC; + } + delete set; + LOG(D1) << "Leaving DtaDevOpal::setTable"; + return 0; +} +uint8_t DtaDevOpal::getTable(vector table, uint16_t startcol, + uint16_t endcol) +{ + LOG(D1) << "Entering DtaDevOpal::getTable"; + uint8_t lastRC; + DtaCommand *get = new DtaCommand(); + if (NULL == get) { + LOG(E) << "Unable to create command object "; + return DTAERROR_OBJECT_CREATE_FAILED; + } + get->reset(OPAL_UID::OPAL_AUTHORITY_TABLE, OPAL_METHOD::GET); + get->changeInvokingUid(table); + get->addToken(OPAL_TOKEN::STARTLIST); + get->addToken(OPAL_TOKEN::STARTLIST); + get->addToken(OPAL_TOKEN::STARTNAME); + get->addToken(OPAL_TOKEN::STARTCOLUMN); + get->addToken(startcol); + get->addToken(OPAL_TOKEN::ENDNAME); + get->addToken(OPAL_TOKEN::STARTNAME); + get->addToken(OPAL_TOKEN::ENDCOLUMN); + get->addToken(endcol); + get->addToken(OPAL_TOKEN::ENDNAME); + get->addToken(OPAL_TOKEN::ENDLIST); + get->addToken(OPAL_TOKEN::ENDLIST); + get->complete(); + if ((lastRC = session->sendCommand(get, response)) != 0) { + delete get; + return lastRC; + } + delete get; + return 0; +} +uint8_t DtaDevOpal::getTableDataStore(vector table, uint32_t startrow, + uint32_t endrow) +{ + LOG(D1) << "Entering DtaDevOpal::getTable"; + uint8_t lastRC; + DtaCommand* get = new DtaCommand(); + if (NULL == get) { + LOG(E) << "Unable to create command object "; + return DTAERROR_OBJECT_CREATE_FAILED; + } + get->reset(OPAL_UID::OPAL_UID_DATASTORE, OPAL_METHOD::GET); + + get->addToken(OPAL_TOKEN::STARTLIST); + get->addToken(OPAL_TOKEN::STARTLIST); + get->addToken(OPAL_TOKEN::STARTNAME); + get->addToken(OPAL_TOKEN::STARTROW); + get->addToken((uint64_t)startrow); + get->addToken(OPAL_TOKEN::ENDNAME); + get->addToken(OPAL_TOKEN::STARTNAME); + get->addToken(OPAL_TOKEN::ENDROW); + get->addToken((uint64_t)endrow); + get->addToken(OPAL_TOKEN::ENDNAME); + get->addToken(OPAL_TOKEN::ENDLIST); + get->addToken(OPAL_TOKEN::ENDLIST); + + get->complete(); + if ((lastRC = session->sendCommand(get, response)) != 0) { + delete get; + return lastRC; + } + delete get; + return 0; +} +uint8_t DtaDevOpal::exec(DtaCommand * cmd, DtaResponse & resp, uint8_t protocol) +{ + uint8_t lastRC; + OPALHeader * hdr = (OPALHeader *) cmd->getCmdBuffer(); + LOG(D3) << endl << "Dumping command buffer"; + IFLOG(D3) DtaHexDump(cmd->getCmdBuffer(), SWAP32(hdr->cp.length) + sizeof (OPALComPacket)); + if((lastRC = sendCmd(IF_SEND, protocol, comID(), cmd->getCmdBuffer(), cmd->outputBufferSize())) != 0) { + LOG(E) << "Command failed on send " << (uint16_t) lastRC; + return lastRC; + } + hdr = (OPALHeader *) cmd->getRespBuffer(); + do { + osmsSleep(25); + memset(cmd->getRespBuffer(), 0, MIN_BUFFER_LENGTH); + lastRC = sendCmd(IF_RECV, protocol, comID(), cmd->getRespBuffer(), MIN_BUFFER_LENGTH); + + } + while ((0 != hdr->cp.outstandingData) && (0 == hdr->cp.minTransfer)); + LOG(D3) << std::endl << "Dumping reply buffer"; + IFLOG(D3) DtaHexDump(cmd->getRespBuffer(), SWAP32(hdr->cp.length) + sizeof (OPALComPacket)); + if (0 != lastRC) { + LOG(E) << "Command failed on recv" << (uint16_t) lastRC; + return lastRC; + } + resp.init(cmd->getRespBuffer()); + return 0; +} + + +uint8_t DtaDevOpal::properties() +{ + LOG(D1) << "Entering DtaDevOpal::properties()"; + uint8_t lastRC; + session = new DtaSession(this); // use the session IO without starting a session + if (NULL == session) { + LOG(E) << "Unable to create session object "; + return DTAERROR_OBJECT_CREATE_FAILED; + } + DtaCommand *props = new DtaCommand(OPAL_UID::OPAL_SMUID_UID, OPAL_METHOD::PROPERTIES); + if (NULL == props) { + LOG(E) << "Unable to create command object "; + delete session; + return DTAERROR_OBJECT_CREATE_FAILED; + } + props->addToken(OPAL_TOKEN::STARTLIST); + props->addToken(OPAL_TOKEN::STARTNAME); + props->addToken(OPAL_TOKEN::HOSTPROPERTIES); + props->addToken(OPAL_TOKEN::STARTLIST); + props->addToken(OPAL_TOKEN::STARTNAME); + props->addToken("MaxComPacketSize"); + props->addToken(2048); + props->addToken(OPAL_TOKEN::ENDNAME); + props->addToken(OPAL_TOKEN::STARTNAME); + props->addToken("MaxPacketSize"); + props->addToken(2028); + props->addToken(OPAL_TOKEN::ENDNAME); + props->addToken(OPAL_TOKEN::STARTNAME); + props->addToken("MaxIndTokenSize"); + props->addToken(1992); + props->addToken(OPAL_TOKEN::ENDNAME); + props->addToken(OPAL_TOKEN::STARTNAME); + props->addToken("MaxPackets"); + props->addToken(1); + props->addToken(OPAL_TOKEN::ENDNAME); + props->addToken(OPAL_TOKEN::STARTNAME); + props->addToken("MaxSubpackets"); + props->addToken(1); + props->addToken(OPAL_TOKEN::ENDNAME); + props->addToken(OPAL_TOKEN::STARTNAME); + props->addToken("MaxMethods"); + props->addToken(1); + props->addToken(OPAL_TOKEN::ENDNAME); + props->addToken(OPAL_TOKEN::ENDLIST); + props->addToken(OPAL_TOKEN::ENDNAME); + props->addToken(OPAL_TOKEN::ENDLIST); + props->complete(); + if ((lastRC = session->sendCommand(props, propertiesResponse)) != 0) { + delete props; + return lastRC; + } + disk_info.Properties = 1; + delete props; + for (uint32_t i = 0; i < propertiesResponse.getTokenCount(); i++) { + if (OPAL_TOKEN::STARTNAME == propertiesResponse.tokenIs(i)) { + if (OPAL_TOKEN::DTA_TOKENID_BYTESTRING != propertiesResponse.tokenIs(i + 1)) + break; + else + if(!strcasecmp("MaxComPacketSize",propertiesResponse.getString(i + 1).c_str())) + tperMaxPacket = propertiesResponse.getUint32(i + 2); + else + if (!strcasecmp("MaxIndTokenSize", propertiesResponse.getString(i + 1).c_str())) { + tperMaxToken = propertiesResponse.getUint32(i + 2); + break; + } + + i += 2; + } + } + LOG(D1) << "Leaving DtaDevOpal::properties()"; + return 0; +} +void DtaDevOpal::puke() +{ + LOG(D1) << "Entering DtaDevOpal::puke()"; + DtaDev::puke(); + if (disk_info.Properties) { + cout << std::endl << "TPer Properties: "; + for (uint32_t i = 0; i < propertiesResponse.getTokenCount(); i++) { + if (OPAL_TOKEN::STARTNAME == propertiesResponse.tokenIs(i)) { + if (OPAL_TOKEN::DTA_TOKENID_BYTESTRING != propertiesResponse.tokenIs(i + 1)) + cout << std::endl << "Host Properties: " << std::endl; + else + cout << " " << propertiesResponse.getString(i + 1) << " = " << propertiesResponse.getUint64(i + 2); + i += 2; + } + if (!(i % 6)) cout << std::endl; + } + } +} + +uint8_t DtaDevOpal::objDump(char *sp, char * auth, char *pass, + char * objID) +{ + + LOG(D1) << "Entering DtaDevEnterprise::objDump"; + LOG(D1) << sp << " " << auth << " " << pass << " " << objID; + uint8_t lastRC; + DtaCommand *get = new DtaCommand(); + if (NULL == get) { + LOG(E) << "Unable to create command object "; + return DTAERROR_OBJECT_CREATE_FAILED; + } + vector authority, object; + uint8_t work; + if (16 != strnlen(auth, 32)) { + LOG(E) << "Authority must be 16 byte ascii string of hex authority uid"; + return DTAERROR_INVALID_PARAMETER; + } + if (16 != strnlen(objID, 32)) { + LOG(E) << "ObjectID must be 16 byte ascii string of hex object uid"; + return DTAERROR_INVALID_PARAMETER; + } + authority.push_back(OPAL_SHORT_ATOM::BYTESTRING8); + for (uint32_t i = 0; i < 16; i += 2) { + work = auth[i] & 0x40 ? 16 * ((auth[i] & 0xf) + 9) : 16 * (auth[i] & 0x0f); + work += auth[i + 1] & 0x40 ? (auth[i + 1] & 0xf) + 9 : auth[i + 1] & 0x0f; + authority.push_back(work); + } + object.push_back(OPAL_SHORT_ATOM::BYTESTRING8); + for (uint32_t i = 0; i < 16; i += 2) { + work = objID[i] & 0x40 ? 16 * ((objID[i] & 0xf) + 9) : 16 * (objID[i] & 0x0f); + work += objID[i + 1] & 0x40 ? (objID[i + 1] & 0xf) + 9 : objID[i + 1] & 0x0f; + object.push_back(work); + } + get->reset(OPAL_UID::OPAL_AUTHORITY_TABLE, OPAL_METHOD::GET); + get->changeInvokingUid(object); + get->addToken(OPAL_TOKEN::STARTLIST); + get->addToken(OPAL_TOKEN::STARTLIST); + get->addToken(OPAL_TOKEN::ENDLIST); + get->addToken(OPAL_TOKEN::ENDLIST); + get->complete(); + LOG(I) << "Command:"; + get->dumpCommand(); + session = new DtaSession(this); + if (NULL == session) { + LOG(E) << "Unable to create session object "; + delete get; + return DTAERROR_OBJECT_CREATE_FAILED; + } + if ((lastRC = session->start((OPAL_UID)atoi(sp), pass, authority)) != 0) { + delete get; + delete session; + return lastRC; + } + if ((lastRC = session->sendCommand(get, response)) != 0) { + delete get; + delete session; + return lastRC; + } + LOG(I) << "Response:"; + get->dumpResponse(); + delete get; + delete session; + LOG(D1) << "Exiting DtaDevEnterprise::objDump"; + return 0; +} +uint8_t DtaDevOpal::rawCmd(char *sp, char * hexauth, char *pass, + char *hexinvokingUID, char *hexmethod, char *hexparms) { + LOG(D1) << "Entering DtaDevEnterprise::rawCmd"; + LOG(D1) << sp << " " << hexauth << " " << pass << " "; + LOG(D1) << hexinvokingUID << " " << hexmethod << " " << hexparms; + uint8_t lastRC; + vector authority, object, invokingUID, method, parms; + uint8_t work; + if (16 != strnlen(hexauth, 32)) { + LOG(E) << "Authority must be 16 byte ascii string of hex authority uid"; + return DTAERROR_INVALID_PARAMETER; + } + authority.push_back(OPAL_SHORT_ATOM::BYTESTRING8); + for (uint32_t i = 0; i < 16; i += 2) { + work = hexauth[i] & 0x40 ? 16 * ((hexauth[i] & 0xf) + 9) : 16 * (hexauth[i] & 0x0f); + work += hexauth[i + 1] & 0x40 ? (hexauth[i + 1] & 0xf) + 9 : hexauth[i + 1] & 0x0f; + authority.push_back(work); + } + if (16 != strnlen(hexinvokingUID, 32)) { + LOG(E) << "invoker must be 16 byte ascii string of invoking uid"; + return DTAERROR_INVALID_PARAMETER; + } + invokingUID.push_back(OPAL_SHORT_ATOM::BYTESTRING8); + for (uint32_t i = 0; i < 16; i += 2) { + work = hexinvokingUID[i] & 0x40 ? 16 * ((hexinvokingUID[i] & 0xf) + 9) : 16 * (hexinvokingUID[i] & 0x0f); + work += hexinvokingUID[i + 1] & 0x40 ? (hexinvokingUID[i + 1] & 0xf) + 9 : hexinvokingUID[i + 1] & 0x0f; + invokingUID.push_back(work); + } + if (16 != strnlen(hexmethod, 32)) { + LOG(E) << "invoker must be 16 byte ascii string of method uid"; + return DTAERROR_INVALID_PARAMETER; + } + method.push_back(OPAL_SHORT_ATOM::BYTESTRING8); + for (uint32_t i = 0; i < 16; i += 2) { + work = hexmethod[i] & 0x40 ? 16 * ((hexmethod[i] & 0xf) + 9) : 16 * (hexmethod[i] & 0x0f); + work += hexmethod[i + 1] & 0x40 ? (hexmethod[i + 1] & 0xf) + 9 : hexmethod[i + 1] & 0x0f; + method.push_back(work); + } + if (1020 < strnlen(hexparms, 1024)) { + LOG(E) << "Parmlist limited to 1020 characters"; + return DTAERROR_INVALID_PARAMETER; + } + if (strnlen(hexparms, 1024) % 2) { + LOG(E) << "Parmlist must be even number of bytes"; + return DTAERROR_INVALID_PARAMETER; + } + + for (uint32_t i = 0; i < strnlen(hexparms, 1024); i += 2) { + work = hexparms[i] & 0x40 ? 16 * ((hexparms[i] & 0xf) + 9) : 16 * (hexparms[i] & 0x0f); + work += hexparms[i + 1] & 0x40 ? (hexparms[i + 1] & 0xf) + 9 : hexparms[i + 1] & 0x0f; + parms.push_back(work); + } + DtaCommand *cmd = new DtaCommand(); + if (NULL == cmd) { + LOG(E) << "Unable to create command object "; + return DTAERROR_OBJECT_CREATE_FAILED; + } + cmd->reset(OPAL_UID::OPAL_AUTHORITY_TABLE, method); + cmd->changeInvokingUid(invokingUID); + cmd->addToken(parms); + cmd->complete(); + session = new DtaSession(this); + if (NULL == session) { + LOG(E) << "Unable to create session object "; + delete cmd; + return DTAERROR_OBJECT_CREATE_FAILED; + } + if ((lastRC = session->start((OPAL_UID)atoi(sp), pass, authority)) != 0) { + delete cmd; + delete session; + return lastRC; + } + LOG(I) << "Command:"; + cmd->dumpCommand(); + if ((lastRC = session->sendCommand(cmd, response)) != 0) { + delete cmd; + delete session; + return lastRC; + } + LOG(I) << "Response:"; + cmd->dumpResponse(); + delete cmd; + delete session; + LOG(D1) << "Exiting DtaDevEnterprise::rawCmd"; + return 0; +} \ No newline at end of file diff --git a/sedutil-master/Common/DtaDevOpal.h b/sedutil-master/Common/DtaDevOpal.h new file mode 100644 index 0000000..6cc1f7e --- /dev/null +++ b/sedutil-master/Common/DtaDevOpal.h @@ -0,0 +1,300 @@ +/* C:B************************************************************************** +This software is Copyright 2014-2017 Bright Plaza Inc. + +This file is part of sedutil. + +sedutil is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +sedutil is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with sedutil. If not, see . + + * C:E********************************************************************** */ +#pragma once +class DtaCommand; +class DtaSession; + +#include "DtaDev.h" +#include "DtaDevOS.h" +#include "DtaStructures.h" +#include "DtaLexicon.h" +#include "DtaResponse.h" // wouldn't take class +#include + +using namespace std; +/** Common code for OPAL SSCs. + * most of the code that works for OPAL 2.0 also works for OPAL 1.0 + * that common code is implemented in this class + */ +class DtaDevOpal : public DtaDevOS { +public: + /** Default Constructor */ + DtaDevOpal(); + /** default Destructor */ + ~DtaDevOpal(); + /** OS specific initialization. + * This function should perform the necessary authority and environment checking + * to allow proper functioning of the program, open the device, perform an ATA + * identify, add the fields from the identify response to the disk info structure + * and if the device is an ATA device perform a call to Discovery0() to complete + * the disk_info structure + * @param devref character representation of the device is standard OS lexicon + */ + void init(const char * devref); + /** Notify the device of the host properties and receive the + * properties of the device as a reply */ + uint8_t properties(); + /** Send a command to the device and wait for the response + * @param cmd the MswdCommand object containg the command + * @param response the DtaResonse object containing the response + * @param protocol The security protocol number to use for the command + */ + uint8_t exec(DtaCommand * cmd, DtaResponse & resp, uint8_t protocol = 0x01); + /** return the communications ID to be used for sessions to this device */ + virtual uint16_t comID() = 0; + /** Change the SID password from it's MSID default + * @param newpassword new password for SID + */ + uint8_t takeOwnership(char * newpassword); + /** retrieve the MSID password */ + uint8_t printDefaultPassword(); + /** test the opal datastore */ + uint8_t readDataStore(char* filename, char* password); + /** write file to datastore */ + uint8_t writeDataStore(char* filename, char* password); + + /** retrieve a single row from a table + * @param table the UID of the table + * @param startcol the starting column of data requested + * @param endcol the ending column of the data requested + */ + uint8_t getTable(vector table, uint16_t startcol, + uint16_t endcol); + /** Set the SID password. + * Requires special handling because password is not always hashed. + * @param oldpassword current SID password + * @param newpassword value password is to be changed to + * @param hasholdpwd is the old password to be hashed before being added to the bytestream + * @param hashnewpwd is the new password to be hashed before being added to the bytestream + */ + uint8_t getTableDataStore(vector table, uint32_t startrow, + uint32_t endrow); + uint8_t setSIDPassword(char * oldpassword, char * newpassword, + uint8_t hasholdpwd = 1, uint8_t hashnewpwd = 1); + /** set a single column in an object table + * @param table the UID of the table + * @param name the column name to be set + * @param value data to be stored the the column + */ + uint8_t setTable(vector table, OPAL_TOKEN name, + vector value); + /** set a single column in an object table + * @param table the UID of the table + * @param name the column name to be set + * @param value data to be stored the the column + */ + uint8_t setTable(vector table, OPAL_TOKEN name, + OPAL_TOKEN value); + + /** Change state of the Locking SP to active. + * Enables locking + * @param password current SID password + */ + uint8_t activateLockingSP(char * password); + /** Change state of the Locking SP to active in Single User Mode. + * Enables locking in Single User Mode + * @param lockingrange the locking range number to activate in SUM + * @param password current SID password + */ + uint8_t activateLockingSP_SUM(uint8_t lockingrange, char * password); + /** Erase a Single User Mode locking range by calling the drive's erase method + * @param lockingrange The Locking Range to erase + * @param password The administrator password for the drive + */ + uint8_t eraseLockingRange_SUM(uint8_t lockingrange, char * password); + /** Restore the state of the Locking SP to factory defaults. + * Enables locking + * @param password current SID password + * @param keep boolean keep the data (NOT FUNCTIONAL) + */ + uint8_t revertLockingSP(char * password, uint8_t keep = 0); + /** get the UID or CPIN ID of a user from their character name + * @param userid Character user name + * @param column UID or CPIN to be returned + * @param userData The UIS or CPIN of the USER + */ + uint8_t getAuth4User(char * userid, uint8_t column, std::vector &userData); + /** Enable a user in the Locking SP + * @param password the password of the Locking SP administrative authority + * @param userid Character name of the user to be enabled + */ + uint8_t enableUser(char * password, char * userid, OPAL_TOKEN status = OPAL_TOKEN::OPAL_TRUE); + /** Primitive to set the MBRDone flag. + * @param state 0 or 1 + * @param Admin1Password Locking SP authority with access to flag + * @param status true or false to enable/disable + */ + uint8_t setMBRDone(uint8_t state, char * Admin1Password); + /** Primitive to set the MBREnable flag. + * @param state 0 or 1 + * @param Admin1Password Locking SP authority with access to flag + */ + uint8_t setMBREnable(uint8_t state, char * Admin1Password); + /** Set the password of a locking SP user. + * @param password current password + * @param userid the userid whose password is to be changed + * @param newpassword value password is to be changed to + */ + uint8_t setPassword(char * password, char * userid, char * newpassword); + /** Set the password of a locking SP user in Single User Mode. + * @param password current user password + * @param userid the userid whose password is to be changed + * @param newpassword value password is to be changed to + */ + uint8_t setNewPassword_SUM(char * password, char * userid, char * newpassword); + /** User command to manipulate the state of a locking range. + * RW|RO|LK are the supported states @see OPAL_LOCKINGSTATE + * @param lockingrange locking range number + * @param lockingstate desired locking state (see above) + * @param Admin1Password password of the locking administrative authority + */ + uint8_t setLockingRange(uint8_t lockingrange, uint8_t lockingstate, + char * Admin1Password); + /** Change the locking state of a locking range in Single User Mode + * @param lockingrange The number of the locking range (0 = global) + * @param lockingstate the locking state to set + * @param password password of user authority for the locking range + */ + uint8_t setLockingRange_SUM(uint8_t lockingrange, uint8_t lockingstate, + char * password); + /** Setup a locking range. Initialize a locking range, set it's start + * LBA and length, initialize it as unlocked with locking disabled. + * @paran lockingrange The Locking Range to be setup + * @param start Starting LBA + * @param length Number of blocks + * @param password Password of administrator + */ + uint8_t setupLockingRange(uint8_t lockingrange, uint64_t start, + uint64_t length, char * password); + /** Setup a locking range in Single User Mode. Initialize a locking range, + * set it's start LBA and length, initialize it as unlocked with locking enabled. + * @paran lockingrange The Locking Range to be setup + * @param start Starting LBA + * @param length Number of blocks + * @paran password Password of administrator + */ + uint8_t setupLockingRange_SUM(uint8_t lockingrange, uint64_t start, + uint64_t length, char * password); + /** List status of locking ranges. + * @param password Password of administrator + */ + uint8_t listLockingRanges(char * password, int16_t rangeid); + /** User command to enable/disable a locking range. + * RW|RO|LK are the supported states @see OPAL_LOCKINGSTATE + * @param lockingrange locking range number + * @param enabled boolean true = enabled, false = disabled + * @param password password of the locking administrative authority + */ + uint8_t configureLockingRange(uint8_t lockingrange, uint8_t enabled, char * password); + /** Generate a new encryption key for a locking range. + * @param lockingrange locking range number + * @param password password of the locking administrative authority + */ + uint8_t rekeyLockingRange(uint8_t lockingrange, char * password); + /** Generate a new encryption key for a Single User Mode locking range. + * @param LR locking range UID in vector format + * @param UID user UID in vector format + * @param password password of the UID authority + */ + uint8_t rekeyLockingRange_SUM(vector LR, vector UID, char * password); + /** Reset the TPER to its factory condition + * ERASES ALL DATA! + * @param password password of authority (SID or PSID) + * @param PSID true or false is the authority the PSID + * */ + /** Enable bands using MSID. + * @param lockingrange locking range number + */ + uint8_t setBandsEnabled(int16_t rangeid, char * password); + uint8_t revertTPer(char * password, uint8_t PSID = 0, uint8_t AdminSP = 0); + /** Erase a locking range + * @param lockingrange The number of the locking range (0 = global) + * @param password Password of administrative authority for locking range + */ + uint8_t eraseLockingRange(uint8_t lockingrange, char * password); + /** Loads a disk image file to the shadow MBR table. + * @param password the password for the administrative authority with access to the table + * @param filename the filename of the disk image + */ + uint8_t loadPBA(char * password, char * filename); + /** User command to prepare the device for management by sedutil. + * Specific to the SSC that the device supports + * @param password the password that is to be assigned to the SSC master entities + */ + uint8_t initialSetup(char * password); + /** User command to prepare the drive for Single User Mode and rekey a SUM locking range. + * @param lockingrange locking range number to enable + * @param start LBA to start locking range + * @param length length (in blocks) for locking range + * @param Admin1Password admin1 password for TPer + * @param password User password to set for locking range + */ + uint8_t setup_SUM(uint8_t lockingrange, uint64_t start, uint64_t length, char *Admin1Password, char * password); + /** Displays the identify and discovery 0 information */ + void puke(); + /** Dumps an object for diagnostic purposes + * @param sp index into the OPALUID table for the SP the object is in + * @param auth the authority ti use for the dump + * @param pass the password for the suthority + * @param objID the UID of the object to dump + * */ + uint8_t objDump(char *sp, char * auth, char *pass, + char * objID); + /** Issue any command to the drive for diagnostic purposes + * @param sp index into the OPALUID table for the SP the object is in + * @param auth the authority ti use for the dump + * @param pass the password for the suthority + * @param invoker caller of the method + * @param method the method to call + * @param plist the parameter list for the command + * + */ + uint8_t rawCmd(char *sp, char * auth, char *pass, + char *invoker, char *method, char *plist); +protected: + /** Primitive to handle the setting of a value in the locking sp. + * @param table_uid UID of the table + * @param name column to be altered + * @param value the value to be set + * @param password password for the administrative authority + * @param msg message to be displayed upon successful update; + */ + uint8_t setLockingSPvalue(OPAL_UID table_uid, OPAL_TOKEN name, OPAL_TOKEN value, + char * password, char * msg = (char *) "New Value Set"); + + uint8_t getDefaultPassword(); + typedef struct lrStatus + { + uint8_t command_status; //return code of locking range query command + uint8_t lockingrange_num; //which locking range is this + uint64_t start; + uint64_t size; + bool RLKEna; + bool WLKEna; + bool RLocked; + bool WLocked; + }lrStatus_t; + /** Get info programatically for single locking range + * @param lockingrange locking range number to check + * @param password Admin1 Password for TPer + */ + lrStatus_t getLockingRange_status(uint8_t lockingrange, char * password); + +}; diff --git a/sedutil-master/Common/DtaDevOpal1.cpp b/sedutil-master/Common/DtaDevOpal1.cpp new file mode 100644 index 0000000..4ca19b6 --- /dev/null +++ b/sedutil-master/Common/DtaDevOpal1.cpp @@ -0,0 +1,35 @@ +/* C:B************************************************************************** +This software is Copyright 2014-2017 Bright Plaza Inc. + +This file is part of sedutil. + +sedutil is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +sedutil is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with sedutil. If not, see . + + * C:E********************************************************************** */ + +#include "DtaDevOpal1.h" + +using namespace std; + + +DtaDevOpal1::DtaDevOpal1 (const char * devref) +{ + DtaDevOpal::init(devref); + assert(isOpal1()); +} + +DtaDevOpal1::~DtaDevOpal1() +{ +} +uint16_t DtaDevOpal1::comID() { return disk_info.OPAL10_basecomID; } diff --git a/sedutil-master/Common/DtaDevOpal1.h b/sedutil-master/Common/DtaDevOpal1.h new file mode 100644 index 0000000..56e6607 --- /dev/null +++ b/sedutil-master/Common/DtaDevOpal1.h @@ -0,0 +1,38 @@ +/* C:B************************************************************************** +This software is Copyright 2014-2017 Bright Plaza Inc. + +This file is part of sedutil. + +sedutil is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +sedutil is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with sedutil. If not, see . + + * C:E********************************************************************** */ +#pragma once +#include "os.h" +#include "DtaDevOpal.h" + +using namespace std; +/** Class representing a disk device, this class is represents a disk that conforms +* to the OPAL 1.0 SSC +* +* testing so far indicates that the functions implemented in this program + * operate the same in OPAL 1.0 and Opal 2.0 +*/ +class DtaDevOpal1 : public DtaDevOpal { +public: + DtaDevOpal1(const char * devref); + ~DtaDevOpal1(); + /** return the communication ID to be used with this device */ + uint16_t comID(); + +}; \ No newline at end of file diff --git a/sedutil-master/Common/DtaDevOpal2.cpp b/sedutil-master/Common/DtaDevOpal2.cpp new file mode 100644 index 0000000..3379b80 --- /dev/null +++ b/sedutil-master/Common/DtaDevOpal2.cpp @@ -0,0 +1,35 @@ +/* C:B************************************************************************** +This software is Copyright 2014-2017 Bright Plaza Inc. + +This file is part of sedutil. + +sedutil is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +sedutil is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with sedutil. If not, see . + + * C:E********************************************************************** */ + +#include "DtaDevOpal2.h" + +using namespace std; + + +DtaDevOpal2::DtaDevOpal2 (const char * devref) +{ + DtaDevOpal::init(devref); + assert(isOpal2()); +} + +DtaDevOpal2::~DtaDevOpal2() +{ +} +uint16_t DtaDevOpal2::comID() { return disk_info.OPAL20_basecomID; } diff --git a/sedutil-master/Common/DtaDevOpal2.h b/sedutil-master/Common/DtaDevOpal2.h new file mode 100644 index 0000000..9765731 --- /dev/null +++ b/sedutil-master/Common/DtaDevOpal2.h @@ -0,0 +1,38 @@ +/* C:B************************************************************************** +This software is Copyright 2014-2017 Bright Plaza Inc. + +This file is part of sedutil. + +sedutil is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +sedutil is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with sedutil. If not, see . + + * C:E********************************************************************** */ +#pragma once +#include "os.h" +#include "DtaDevOpal.h" + +using namespace std; +/** Class representing a disk device, this class is represents a disk that conforms +* to the OPAL 2.0 SSC +* +* testing so far indicates that the functions implemented in this program +* function the same in OPAL 1.0 and Opal 2.0 +*/ +class DtaDevOpal2 : public DtaDevOpal { +public: + DtaDevOpal2(const char * devref); + ~DtaDevOpal2(); + /** return the communication ID to be used with this device */ + uint16_t comID(); + +}; \ No newline at end of file diff --git a/sedutil-master/Common/DtaDiskType.cpp b/sedutil-master/Common/DtaDiskType.cpp new file mode 100644 index 0000000..9753b63 --- /dev/null +++ b/sedutil-master/Common/DtaDiskType.cpp @@ -0,0 +1,38 @@ +/* C:B************************************************************************** +This software is Copyright 2014-2017 Bright Plaza Inc. + +This file is part of sedutil. + +sedutil is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +sedutil is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with sedutil. If not, see . + +* C:E********************************************************************** */ +#include "DtaDiskType.h" + +using namespace std; + +DtaDiskType::DtaDiskType() {} +DtaDiskType::~DtaDiskType() {} +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4100) +#endif +void DtaDiskType::init(const char * devref) {} +uint8_t DtaDiskType::sendCmd(ATACOMMAND cmd, uint8_t protocol, uint16_t comID, + void * buffer, uint32_t bufferlen) { + return 10; +} +void DtaDiskType::identify(OPAL_DiskInfo& disk_info) {} +#ifdef _MSC_VER +#pragma warning(pop) +#endif diff --git a/sedutil-master/Common/DtaDiskType.h b/sedutil-master/Common/DtaDiskType.h new file mode 100644 index 0000000..5eaafea --- /dev/null +++ b/sedutil-master/Common/DtaDiskType.h @@ -0,0 +1,51 @@ +/* C:B************************************************************************** +This software is Copyright 2014-2017 Bright Plaza Inc. + +This file is part of sedutil. + +sedutil is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +sedutil is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with sedutil. If not, see . + +* C:E********************************************************************** */ +#pragma once +#include "os.h" +#include "DtaStructures.h" +/** Device specific implementation of disk access functions. */ +class DtaDiskType { +public: + DtaDiskType(); + virtual ~DtaDiskType(); + /** device specific initialization. + * This function should perform the necessary authority and environment checking + * to allow proper functioning of the program, open the device, perform an + * identify, add the fields from the identify response to the disk info structure + * and if the device is an ATA device perform a call to Discovery0() to complete + * the disk_info structure + * @param devref character representation of the device is standard OS lexicon + */ + virtual void init(const char * devref); + /** OS specific method to send an ATA command to the device + * @param cmd command to be sent to the device + * @param protocol security protocol to be used in the command + * @param comID communications ID to be used + * @param buffer input/output buffer + * @param bufferlen length of the input/output buffer + */ + virtual uint8_t sendCmd(ATACOMMAND cmd, uint8_t protocol, uint16_t comID, + void * buffer, uint32_t bufferlen); + + /** OS specific routine to send an ATA identify to the device + * @param disk_info structure to fill in with drive information + */ + virtual void identify(OPAL_DiskInfo& disk_info); +}; diff --git a/sedutil-master/Common/DtaEndianFixup.h b/sedutil-master/Common/DtaEndianFixup.h new file mode 100644 index 0000000..58eb3ff --- /dev/null +++ b/sedutil-master/Common/DtaEndianFixup.h @@ -0,0 +1,49 @@ +/* C:B************************************************************************** +This software is Copyright 2014-2017 Bright Plaza Inc. + +This file is part of sedutil. + +sedutil is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +sedutil is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with sedutil. If not, see . + +* C:E********************************************************************** */ +/* These are a few macros to fixup the endianess of the data + * returned by the drive as specified in the TCG OPAL SSC standards + * Since this is a low use utility program it shouldn't be to + * ugly that these are macros + */ + +/* + * Windows provides system call in the network stack to do this but + * I've never had much luck when the winsock headers get in the mix + */ +// +//TODO: add a test on the endianess of the system and define +// empty macros if the system is big endian +#pragma once +#ifdef __gnu_linux__ +#include +#if __BYTE_ORDER != __LITTLE_ENDIAN +#error This code does not support big endian architectures +#endif +#endif +/** change the "endianess" of a 16bit field */ +#define SWAP16(x) ((uint16_t) ((x & 0x00ff) << 8) | ((x & 0xff00) >> 8)) +/** change the "endianess" of a 32bit field */ +#define SWAP32(x) ((uint32_t) (((x) & 0x000000ff) << 24) | (((x) & 0x0000ff00) << 8) \ + | (((x) & 0x00ff0000) >> 8) | (((x) & 0xff000000) >> 24)) +/** change the "endianess" of a 64bit field */ +#define SWAP64(x) (uint64_t) \ + ((uint64_t) (SWAP32((x & 0x00000000ffffffff)) << 32) | \ + ((uint64_t) (SWAP32((x >> 32))) ) \ + ) diff --git a/sedutil-master/Common/DtaHashPwd.cpp b/sedutil-master/Common/DtaHashPwd.cpp new file mode 100644 index 0000000..1997393 --- /dev/null +++ b/sedutil-master/Common/DtaHashPwd.cpp @@ -0,0 +1,161 @@ +/* C:B************************************************************************** +This software is Copyright 2014-2017 Bright Plaza Inc. + +This file is part of sedutil. + +sedutil is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +sedutil is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with sedutil. If not, see . + + * C:E********************************************************************** */ +#include "os.h" +#include +#include +#include "DtaHashPwd.h" +#include "DtaLexicon.h" +#include "DtaOptions.h" +#include "DtaDev.h" +#include "log.h" + +extern "C" { +#include "pbkdf2.h" +#include "sha1.h" +} +using namespace std; + +void DtaHashPassword(vector &hash, char * password, vector salt, + unsigned int iter, uint8_t hashsize) +{ + LOG(D1) << " Entered DtaHashPassword"; + // if the hashsize can be > 255 the token overhead logic needs to be fixed + assert(1 == sizeof(hashsize)); + if (253 < hashsize) { LOG(E) << "Hashsize > 253 incorrect token generated"; } + + hash.clear(); + // don't hash the devault OPAL password '' + if (0 == strnlen(password, 32)) { + goto exit; + } + hash.reserve(hashsize + 2); // hope this will prevent reallocation + for (uint16_t i = 0; i < hashsize; i++) { + hash.push_back(' '); + } + + cf_pbkdf2_hmac((uint8_t *)password, strnlen(password, 256), + salt.data(), salt.size(), + iter, + hash.data(), hash.size(), + &cf_sha1); + +// gc_pbkdf2_sha1(password, strnlen(password, 256), (const char *)salt.data(), salt.size(), iter, +// (char *)hash.data(), hash.size()); +exit: // add the token overhead + hash.insert(hash.begin(), (uint8_t)hash.size()); + hash.insert(hash.begin(), 0xd0); +} + +void DtaHashPwd(vector &hash, char * password, DtaDev * d) +{ + LOG(D1) << " Entered DtaHashPwd"; + char *serNum; + + if (d->no_hash_passwords) { + hash.clear(); + for (uint16_t i = 0; i < strnlen(password, 32); i++) + hash.push_back(password[i]); + // add the token overhead + hash.insert(hash.begin(), (uint8_t)hash.size()); + hash.insert(hash.begin(), 0xd0); + LOG(D1) << " Exit DtaHashPwd"; + return; + } + serNum = d->getSerialNum(); + vector salt(serNum, serNum + 20); + // vector salt(DEFAULTSALT); + DtaHashPassword(hash, password, salt); + LOG(D1) << " Exit DtaHashPwd"; // log for hash timing +} + +struct PBKDF_TestTuple +{ + uint8_t hashlen; + unsigned int iterations; + const char *Password, *Salt, *hexDerivedKey; +}; + +int testresult(std::vector &result, const char * expected, size_t len) { + char work[50]; + if (len > 50) return 1; + int p = 0; + printf("Expected Result: %s\nActual Result : ", expected); + for (uint32_t i = 0; i < len; i++) { printf("%02x", result[i + 2]); }; printf("\n"); + for (uint32_t i = 0; i < len * 2; i += 2) { + work[p] = expected[i] & 0x40 ? 16 * ((expected[i] & 0xf) + 9) : 16 * (expected[i] & 0xf); + work[p] += expected[i + 1] & 0x40 ? (expected[i + 1] & 0xf) + 9 : expected[i + 1] & 0xf; + p++; + } + return memcmp(result.data()+2, work, len); +} + +int Testsedutil(const PBKDF_TestTuple *testSet, unsigned int testSetSize) +{ + int pass = 1; + std::vector hash, seaSalt; + + for (unsigned int i = 0; i < testSetSize; i++) { + const PBKDF_TestTuple &tuple = testSet[i]; + hash.clear(); + seaSalt.clear(); + for (uint16_t j = 0; j < strnlen(tuple.Salt, 255); j++) { + seaSalt.push_back(tuple.Salt[j]); + } + printf("Password %s Salt %s Iterations %i Length %i\n", (char *)tuple.Password, + (char *) tuple.Salt, tuple.iterations, tuple.hashlen); + DtaHashPassword(hash, (char *) tuple.Password, seaSalt, tuple.iterations, tuple.hashlen); + int fail = (testresult(hash, tuple.hexDerivedKey, tuple.hashlen) == 0); + pass = pass & fail; + } + + return pass; +} +int TestPBKDF2() +{ + int pass = 1; + // from draft-ietf-smime-password-03.txt, at http://www.imc.org/draft-ietf-smime-password + PBKDF_TestTuple testSet[] = { + // Draft PKCS #5 PBKDF2 Test Vectors http://tools.ietf.org/html/draft-josefsson-pbkdf2-test-vectors-06 + // "password" (8 octets) S = "salt" (4 octets) c = 1 DK = 0c60c80f961f0e71f3a9b524af6012062fe037a6 + { 20, 1, "password", "salt", "0c60c80f961f0e71f3a9b524af6012062fe037a6"}, + // "password" (8 octets) S = "salt" (4 octets) c = 2 DK = ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957 + { 20, 2, "password", "salt", "ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957"}, + // "password" (8 octets) S = "salt" (4 octets) c = 4096 DK = 4b007901b765489abead49d926f721d065a429c1 + { 20, 4096, "password", "salt", "4b007901b765489abead49d926f721d065a429c1"}, + // "password" (8 octets) S = "salt" (4 octets) c = 16777216 DK = eefe3d61cd4da4e4e9945b3d6ba2158c2634e984 + //{ 20, 16777216, "password", "salt", "eefe3d61cd4da4e4e9945b3d6ba2158c2634e984" }, + // "passwordPASSWORDpassword" (24 octets) S = "saltSALTsaltSALTsaltSALTsaltSALTsalt" (36 octets) c = 4096 DK = 3d2eec4fe41c849b80c8d83662c0e44a8b291a964cf2f07038 + { 25, 4096, "passwordPASSWORDpassword", "saltSALTsaltSALTsaltSALTsaltSALTsalt", + "3d2eec4fe41c849b80c8d83662c0e44a8b291a964cf2f07038"}, + // "pass\0word" (9 octets) S = "sa\0lt" (5 octets) c = 4096 DK = 56fa6aa75548099dcc37d7f03425e0c3 + //{ 16, 4096, "pass\0word", "sa\0lt", "56fa6aa75548099dcc37d7f03425e0c3" }, + // program receives char * from OS so this test would fail but is not possible IRL + }; + + cout << "\nPKCS #5 PBKDF2 validation suite running ... \n\n"; + pass = Testsedutil(testSet, sizeof (testSet) / sizeof (testSet[0])) && pass; + cout << "\nPKCS #5 PBKDF2 validation suite ... "; + if (pass) + cout << "passed\n"; + else + cout << "**FAILED**\n"; + return 0; +} + diff --git a/sedutil-master/Common/DtaHashPwd.h b/sedutil-master/Common/DtaHashPwd.h new file mode 100644 index 0000000..3815f7c --- /dev/null +++ b/sedutil-master/Common/DtaHashPwd.h @@ -0,0 +1,47 @@ +/* C:B************************************************************************** +This software is Copyright 2014-2017 Bright Plaza Inc. + +This file is part of sedutil. + +sedutil is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +sedutil is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with sedutil. If not, see . + + * C:E********************************************************************** */ +#pragma once +#include +class DtaDev; + +using namespace std; +/** Hash the password using the drive serial number as salt. + * This is far from ideal but it's better that a single salt as + * it should prevent attacking the password with a prebuilt table + * + * This is an intermediary pass through so that the real hash + * function (DtaHashPassword) can be tested and verified. + * @param hash The field whare the hash is to be placed + * @param password The password to be hashed + * @param device the device where the password is to be used + */ +void DtaHashPwd(vector &hash, char * password, DtaDev * device); +/** Hash a passwor using the PBDKF2 function + * + * @param hash Field where hash returned + * @param password password to be hashed + * @param salt salt to be used in the hash + * @param iter number of iterations to be preformed + * @param hashsize size of hash to be returned + */ +void DtaHashPassword(vector &hash, char * password, vector salt, + unsigned int iter = 75000, uint8_t hashsize = 32); +/** Test the hshing function using publicly available test cased and report */ +int TestPBKDF2(); diff --git a/sedutil-master/Common/DtaHexDump.cpp b/sedutil-master/Common/DtaHexDump.cpp new file mode 100644 index 0000000..b7794e4 --- /dev/null +++ b/sedutil-master/Common/DtaHexDump.cpp @@ -0,0 +1,54 @@ +/* C:B************************************************************************** +This software is Copyright 2014-2017 Bright Plaza Inc. + +This file is part of sedutil. + +sedutil is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +sedutil is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with sedutil. If not, see . + +* C:E********************************************************************** */ +#include "os.h" +#include +#include +void DtaHexDump(void * address, int length) { + uint8_t display[17]; + uint8_t * cpos = (uint8_t *)address; + uint8_t * epos = cpos + length; + LOG(D1) << "Entering hexDump"; + int rpos = 0; + int dpos = 0; + fprintf( stderr,"%04x ",rpos); + while (cpos < epos){ + fprintf( stderr,"%02x", cpos[0]); + if (!((++rpos) % 4))fprintf( stderr," "); + display[dpos++] = (isprint(cpos[0]) ? cpos[0] : 0x2e ); + cpos += 1; + if (16 == dpos) { + dpos = 0; + display[16] = 0x00; + fprintf( stderr," %s \n", display); + if(cpos < epos) fprintf( stderr,"%04x ", rpos); + memset(&display,0,sizeof(display)); + } + } + if (dpos != 0) { + if (dpos % 4) fprintf( stderr," "); + fprintf( stderr," "); + for (int i = dpos ; i < 15; i++) { + if (!(i % 4)) fprintf( stderr," "); + fprintf( stderr," "); + } + display[dpos] = 0x00; + fprintf( stderr," %s\n", display); + } +} \ No newline at end of file diff --git a/sedutil-master/Common/DtaHexDump.h b/sedutil-master/Common/DtaHexDump.h new file mode 100644 index 0000000..bcb4cc1 --- /dev/null +++ b/sedutil-master/Common/DtaHexDump.h @@ -0,0 +1,26 @@ +/* C:B************************************************************************** +This software is Copyright 2014-2017 Bright Plaza Inc. + +This file is part of sedutil. + +sedutil is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +sedutil is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with sedutil. If not, see . + + * C:E********************************************************************** */ + +#pragma once +/** Print a hexdump of an area of memory + * @param address Starting address for the dump + * @param length Length of the area to be dumped + */ +void DtaHexDump(void * address, int length); \ No newline at end of file diff --git a/sedutil-master/Common/DtaLexicon.h b/sedutil-master/Common/DtaLexicon.h new file mode 100644 index 0000000..fb9b1c8 --- /dev/null +++ b/sedutil-master/Common/DtaLexicon.h @@ -0,0 +1,270 @@ +/* C:B************************************************************************** +This software is Copyright 2014-2017 Bright Plaza Inc. + +This file is part of sedutil. + +sedutil is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +sedutil is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with sedutil. If not, see . + + * C:E********************************************************************** */ +#pragma once +/* + * Define the structures and enums needed to map the + * Opal SSC Pseudo code to procedures. + * + * no effort has been made to be complete, these are the values + * that are required for the basic functionality provided in this + * program. + */ + +/** User IDs used in the TCG storage SSCs */ +static const uint8_t OPALUID[][8]{ + // users + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff}, /**< session management */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }, /**< special "thisSP" syntax */ + { 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x00, 0x01 }, /**< Administrative SP */ + { 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x00, 0x02 }, /**< Locking SP */ + { 0x00, 0x00, 0x02, 0x05, 0x00, 0x01, 0x00, 0x01 }, /**< ENTERPRISE Locking SP */ + { 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x01 }, /** + +This file is part of sedutil. + +sedutil is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +sedutil is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with sedutil. If not, see . + + * C:E********************************************************************** */ +#include "os.h" +#include "DtaOptions.h" +#include "DtaLexicon.h" +#define GIT_VERSION "JEFF_VERSION 1.0.0" +//#include "Version.h" +void usage() +{ + printf("sedutil v%s Copyright 2014-2017 Bright Plaza Inc. \n", GIT_VERSION); + printf("a utility to manage self encrypting drives that conform\n"); + printf("to the Trusted Computing Group OPAL 2.0 SSC specification\n"); + printf("General Usage: (see readme for extended commandset)\n"); + printf("sedutil-cli <-v> <-n> \n"); + printf("-v (optional) increase verbosity, one to five v's\n"); + printf("-n (optional) no password hashing. Passwords will be sent in clear text!\n"); + printf("-l (optional) log style output to stderr only\n"); + printf("actions \n"); + printf("--scan \n"); + printf(" Scans the devices on the system \n"); + printf(" identifying Opal compliant devices \n"); + printf("--query \n"); + printf(" Display the Discovery 0 response of a device\n"); + printf("--isValidSED \n"); + printf(" Verify whether the given device is SED or not\n"); + printf("--listLockingRanges \n"); + printf(" List all Locking Ranges\n"); + printf("--listLockingRange <0...n> \n"); + printf(" List all Locking Ranges\n"); + printf(" 0 = GLobal 1..n = LRn \n"); + printf("--rekeyLockingRange <0...n> \n"); + printf(" 0 = GLobal 1..n = LRn \n"); + printf(" Rekey Locking Range\n"); + printf("--setBandsEnabled \n"); + printf(" Set Enabled for all Locking Ranges\n"); + printf(" (passwort = \"\" for MSID) \n"); + printf("--setBandEnabled <0...n> \n"); + printf(" Set Enabled for Locking Range[n]\n"); + printf(" (passwort = \"\" for MSID) \n"); + printf("--eraseLockingRange <0...n> \n"); + printf(" Erase a Locking Range\n"); + printf(" 0 = GLobal 1..n = LRn \n"); + printf("--setupLockingRange <0...n> \n"); + printf(" Setup a new Locking Range\n"); + printf(" 0 = GLobal 1..n = LRn \n"); + printf("--initialSetup \n"); + printf(" Setup the device for use with sedutil\n"); + printf(" is new SID and Admin1 password\n"); + printf("--setSIDPassword \n"); + printf(" Change the SID password\n"); + printf("--setAdmin1Pwd \n"); + printf(" Change the Admin1 password\n"); + printf("--setPassword \n"); + printf(" Change the Enterprise password for userid\n"); + printf(" \"EraseMaster\" or \"BandMaster\", 0 <= n <= 1023\n"); + printf("--setLockingRange <0...n> \n"); + printf(" Set the status of a Locking Range\n"); + printf(" 0 = GLobal 1..n = LRn \n"); + printf("--enableLockingRange <0...n> \n"); + printf(" Enable a Locking Range\n"); + printf(" 0 = GLobal 1..n = LRn \n"); + printf("--disableLockingRange <0...n> \n"); + printf(" Disable a Locking Range\n"); + printf(" 0 = GLobal 1..n = LRn \n"); + printf("--setMBREnable \n"); + printf(" Enable|Disable MBR shadowing \n"); + printf("--setMBRDone \n"); + printf(" set|unset MBRDone\n"); + printf("--loadPBAimage \n"); + printf(" Write to MBR Shadow area\n"); + printf("--revertTPer \n"); + printf(" set the device back to factory defaults \n"); + printf(" This **ERASES ALL DATA** \n"); + printf("--revertNoErase \n"); + printf(" deactivate the Locking SP \n"); + printf(" without erasing the data \n"); + printf(" on GLOBAL RANGE *ONLY* \n"); + printf("--yesIreallywanttoERASEALLmydatausingthePSID \n"); + printf(" revert the device using the PSID *ERASING* *ALL* the data \n"); + printf("--printDefaultPassword \n"); + printf(" print MSID \n"); + printf("\n"); + printf("--writeDataStore \n"); + printf(" write a file to the datastore\n"); + printf("--readDataStore \n"); + printf(" read from the datastore to a file\n"); + printf("\n"); + printf("Examples \n"); + printf("sedutil-cli --scan \n"); + printf("sedutil-cli --query %s \n", DEVICEEXAMPLE); + printf("sedutil-cli --yesIreallywanttoERASEALLmydatausingthePSID %s \n", DEVICEEXAMPLE); + printf("sedutil-cli --initialSetup %s \n", DEVICEEXAMPLE); + return; +} + +uint8_t DtaOptions(int argc, char * argv[], DTA_OPTIONS * opts) +{ + memset(opts, 0, sizeof (DTA_OPTIONS)); + uint16_t loggingLevel = 2; + uint8_t baseOptions = 2; // program and option + CLog::Level() = CLog::FromInt(loggingLevel); + RCLog::Level() = RCLog::FromInt(loggingLevel); + if (2 > argc) { + usage(); + return DTAERROR_INVALID_COMMAND; + } + for (uint8_t i = 1; i < argc; i++) { + if (!(strcmp("-h", argv[i])) || !(strcmp("--help", argv[i]))) { + usage(); + return DTAERROR_INVALID_COMMAND; + } + else if ('v' == argv[i][1]) + { + baseOptions += 1; + loggingLevel += (uint16_t)(strlen(argv[i]) - 1); + if (loggingLevel > 7) loggingLevel = 7; + CLog::Level() = CLog::FromInt(loggingLevel); + RCLog::Level() = RCLog::FromInt(loggingLevel); + LOG(D) << "Log level set to " << CLog::ToString(CLog::FromInt(loggingLevel)); + LOG(D) << "sedutil version : " << GIT_VERSION; + } + else if (!(strcmp("-n", argv[i]))) { + baseOptions += 1; + opts->no_hash_passwords = true; + LOG(D) << "Password hashing is disabled"; + } + else if (!strcmp("-l", argv[i])) { + baseOptions += 1; + opts->output_format = sedutilNormal; + outputFormat = sedutilNormal; + } + else if (!(('-' == argv[i][0]) && ('-' == argv[i][1])) && + (0 == opts->action)) + { + LOG(E) << "Argument " << (uint16_t) i << " (" << argv[i] << ") should be a command"; + return DTAERROR_INVALID_COMMAND; + } + BEGIN_OPTION(initialSetup, 2) OPTION_IS(password) OPTION_IS(device) END_OPTION + BEGIN_OPTION(setSIDPassword, 3) OPTION_IS(password) OPTION_IS(newpassword) + OPTION_IS(device) END_OPTION + BEGIN_OPTION(setup_SUM, 6) + TESTARG(0, lockingrange, 0) + TESTARG(1, lockingrange, 1) + TESTARG(2, lockingrange, 2) + TESTARG(3, lockingrange, 3) + TESTARG(4, lockingrange, 4) + TESTARG(5, lockingrange, 5) + TESTARG(6, lockingrange, 6) + TESTARG(7, lockingrange, 7) + TESTARG(8, lockingrange, 8) + TESTARG(9, lockingrange, 9) + TESTARG(10, lockingrange, 10) + TESTARG(11, lockingrange, 11) + TESTARG(12, lockingrange, 12) + TESTARG(13, lockingrange, 13) + TESTARG(14, lockingrange, 14) + TESTARG(15, lockingrange, 15) + TESTFAIL("Invalid Locking Range (0-15)") + OPTION_IS(lrstart) + OPTION_IS(lrlength) + OPTION_IS(password) + OPTION_IS(newpassword) + OPTION_IS(device) + END_OPTION + BEGIN_OPTION(setAdmin1Pwd, 3) OPTION_IS(password) OPTION_IS(newpassword) + OPTION_IS(device) END_OPTION + BEGIN_OPTION(loadPBAimage, 3) OPTION_IS(password) OPTION_IS(pbafile) + OPTION_IS(device) END_OPTION + BEGIN_OPTION(revertTPer, 2) OPTION_IS(password) OPTION_IS(device) END_OPTION + BEGIN_OPTION(revertNoErase, 2) OPTION_IS(password) OPTION_IS(device) END_OPTION + BEGIN_OPTION(PSIDrevert, 2) OPTION_IS(password) OPTION_IS(device) END_OPTION + BEGIN_OPTION(PSIDrevertAdminSP, 2) OPTION_IS(password) OPTION_IS(device) END_OPTION + BEGIN_OPTION(yesIreallywanttoERASEALLmydatausingthePSID, 2) OPTION_IS(password) + OPTION_IS(device) END_OPTION + BEGIN_OPTION(enableuser, 2) OPTION_IS(password) OPTION_IS(userid) + OPTION_IS(device) END_OPTION + BEGIN_OPTION(activateLockingSP, 2) OPTION_IS(password) OPTION_IS(device) END_OPTION + BEGIN_OPTION(activateLockingSP_SUM, 3) + TESTARG(0, lockingrange, 0) + TESTARG(1, lockingrange, 1) + TESTARG(2, lockingrange, 2) + TESTARG(3, lockingrange, 3) + TESTARG(4, lockingrange, 4) + TESTARG(5, lockingrange, 5) + TESTARG(6, lockingrange, 6) + TESTARG(7, lockingrange, 7) + TESTARG(8, lockingrange, 8) + TESTARG(9, lockingrange, 9) + TESTARG(10, lockingrange, 10) + TESTARG(11, lockingrange, 11) + TESTARG(12, lockingrange, 12) + TESTARG(13, lockingrange, 13) + TESTARG(14, lockingrange, 14) + TESTARG(15, lockingrange, 15) + TESTFAIL("Invalid Locking Range (0-15)") + OPTION_IS(password) OPTION_IS(device) END_OPTION + BEGIN_OPTION(eraseLockingRange_SUM, 3) + TESTARG(0, lockingrange, 0) + TESTARG(1, lockingrange, 1) + TESTARG(2, lockingrange, 2) + TESTARG(3, lockingrange, 3) + TESTARG(4, lockingrange, 4) + TESTARG(5, lockingrange, 5) + TESTARG(6, lockingrange, 6) + TESTARG(7, lockingrange, 7) + TESTARG(8, lockingrange, 8) + TESTARG(9, lockingrange, 9) + TESTARG(10, lockingrange, 10) + TESTARG(11, lockingrange, 11) + TESTARG(12, lockingrange, 12) + TESTARG(13, lockingrange, 13) + TESTARG(14, lockingrange, 14) + TESTARG(15, lockingrange, 15) + TESTFAIL("Invalid Locking Range (1-15)") + OPTION_IS(password) OPTION_IS(device) END_OPTION + BEGIN_OPTION(query, 1) OPTION_IS(device) END_OPTION + BEGIN_OPTION(scan, 0) END_OPTION + BEGIN_OPTION(isValidSED, 1) OPTION_IS(device) END_OPTION + BEGIN_OPTION(eraseLockingRange, 3) + TESTARG(0, lockingrange, 0) + TESTARG(1, lockingrange, 1) + TESTARG(2, lockingrange, 2) + TESTARG(3, lockingrange, 3) + TESTARG(4, lockingrange, 4) + TESTARG(5, lockingrange, 5) + TESTARG(6, lockingrange, 6) + TESTARG(7, lockingrange, 7) + TESTARG(8, lockingrange, 8) + TESTARG(9, lockingrange, 9) + TESTARG(10, lockingrange, 10) + TESTARG(11, lockingrange, 11) + TESTARG(12, lockingrange, 12) + TESTARG(13, lockingrange, 13) + TESTARG(14, lockingrange, 14) + TESTARG(15, lockingrange, 15) + TESTFAIL("Invalid Locking Range (0-15)") + OPTION_IS(password) + OPTION_IS(device) + END_OPTION + BEGIN_OPTION(takeOwnership, 2) OPTION_IS(password) OPTION_IS(device) END_OPTION + BEGIN_OPTION(revertLockingSP, 2) OPTION_IS(password) OPTION_IS(device) END_OPTION + BEGIN_OPTION(setPassword, 4) OPTION_IS(password) OPTION_IS(userid) + OPTION_IS(newpassword) OPTION_IS(device) END_OPTION + BEGIN_OPTION(setPassword_SUM, 4) OPTION_IS(password) OPTION_IS(userid) + OPTION_IS(newpassword) OPTION_IS(device) END_OPTION + BEGIN_OPTION(validatePBKDF2, 0) END_OPTION + BEGIN_OPTION(setMBREnable, 3) + TESTARG(ON, mbrstate, 1) + TESTARG(on, mbrstate, 1) + TESTARG(off, mbrstate, 0) + TESTARG(OFF, mbrstate, 0) + TESTFAIL("Invalid setMBREnable argument not ") + OPTION_IS(password) + OPTION_IS(device) + END_OPTION + BEGIN_OPTION(setMBRDone, 3) + TESTARG(ON, mbrstate, 1) + TESTARG(on, mbrstate, 1) + TESTARG(off, mbrstate, 0) + TESTARG(OFF, mbrstate, 0) + TESTFAIL("Invalid setMBRDone argument not ") + OPTION_IS(password) + OPTION_IS(device) + END_OPTION + BEGIN_OPTION(setLockingRange, 4) + TESTARG(0, lockingrange, 0) + TESTARG(1, lockingrange, 1) + TESTARG(2, lockingrange, 2) + TESTARG(3, lockingrange, 3) + TESTARG(4, lockingrange, 4) + TESTARG(5, lockingrange, 5) + TESTARG(6, lockingrange, 6) + TESTARG(7, lockingrange, 7) + TESTARG(8, lockingrange, 8) + TESTARG(9, lockingrange, 9) + TESTARG(10, lockingrange, 10) + TESTARG(11, lockingrange, 11) + TESTARG(12, lockingrange, 12) + TESTARG(13, lockingrange, 13) + TESTARG(14, lockingrange, 14) + TESTARG(15, lockingrange, 15) + TESTFAIL("Invalid Locking Range (0-15)") + TESTARG(RW, lockingstate, OPAL_LOCKINGSTATE::READWRITE) + TESTARG(rw, lockingstate, OPAL_LOCKINGSTATE::READWRITE) + TESTARG(RO, lockingstate, OPAL_LOCKINGSTATE::READONLY) + TESTARG(ro, lockingstate, OPAL_LOCKINGSTATE::READONLY) + TESTARG(LK, lockingstate, OPAL_LOCKINGSTATE::LOCKED) + TESTARG(lk, lockingstate, OPAL_LOCKINGSTATE::LOCKED) + TESTFAIL("Invalid locking state ") + OPTION_IS(password) + OPTION_IS(device) + END_OPTION + BEGIN_OPTION(setLockingRange_SUM, 4) + TESTARG(0, lockingrange, 0) + TESTARG(1, lockingrange, 1) + TESTARG(2, lockingrange, 2) + TESTARG(3, lockingrange, 3) + TESTARG(4, lockingrange, 4) + TESTARG(5, lockingrange, 5) + TESTARG(6, lockingrange, 6) + TESTARG(7, lockingrange, 7) + TESTARG(8, lockingrange, 8) + TESTARG(9, lockingrange, 9) + TESTARG(10, lockingrange, 10) + TESTARG(11, lockingrange, 11) + TESTARG(12, lockingrange, 12) + TESTARG(13, lockingrange, 13) + TESTARG(14, lockingrange, 14) + TESTARG(15, lockingrange, 15) + TESTFAIL("Invalid Locking Range (0-15)") + TESTARG(RW, lockingstate, OPAL_LOCKINGSTATE::READWRITE) + TESTARG(rw, lockingstate, OPAL_LOCKINGSTATE::READWRITE) + TESTARG(RO, lockingstate, OPAL_LOCKINGSTATE::READONLY) + TESTARG(ro, lockingstate, OPAL_LOCKINGSTATE::READONLY) + TESTARG(LK, lockingstate, OPAL_LOCKINGSTATE::LOCKED) + TESTARG(lk, lockingstate, OPAL_LOCKINGSTATE::LOCKED) + TESTFAIL("Invalid locking state ") + OPTION_IS(password) + OPTION_IS(device) + END_OPTION + BEGIN_OPTION(enableLockingRange, 3) + TESTARG(0, lockingrange, 0) + TESTARG(1, lockingrange, 1) + TESTARG(2, lockingrange, 2) + TESTARG(3, lockingrange, 3) + TESTARG(4, lockingrange, 4) + TESTARG(5, lockingrange, 5) + TESTARG(6, lockingrange, 6) + TESTARG(7, lockingrange, 7) + TESTARG(8, lockingrange, 8) + TESTARG(9, lockingrange, 9) + TESTARG(10, lockingrange, 10) + TESTARG(11, lockingrange, 11) + TESTARG(12, lockingrange, 12) + TESTARG(13, lockingrange, 13) + TESTARG(14, lockingrange, 14) + TESTARG(15, lockingrange, 15) + TESTFAIL("Invalid Locking Range (0-15)") + OPTION_IS(password) + OPTION_IS(device) + END_OPTION + BEGIN_OPTION(disableLockingRange, 3) + TESTARG(0, lockingrange, 0) + TESTARG(1, lockingrange, 1) + TESTARG(2, lockingrange, 2) + TESTARG(3, lockingrange, 3) + TESTARG(4, lockingrange, 4) + TESTARG(5, lockingrange, 5) + TESTARG(6, lockingrange, 6) + TESTARG(7, lockingrange, 7) + TESTARG(8, lockingrange, 8) + TESTARG(9, lockingrange, 9) + TESTARG(10, lockingrange, 10) + TESTARG(11, lockingrange, 11) + TESTARG(12, lockingrange, 12) + TESTARG(13, lockingrange, 13) + TESTARG(14, lockingrange, 14) + TESTARG(15, lockingrange, 15) + TESTFAIL("Invalid Locking Range (0-15)") + OPTION_IS(password) + OPTION_IS(device) + END_OPTION + BEGIN_OPTION(setupLockingRange, 5) + TESTARG(0, lockingrange, 0) + TESTARG(1, lockingrange, 1) + TESTARG(2, lockingrange, 2) + TESTARG(3, lockingrange, 3) + TESTARG(4, lockingrange, 4) + TESTARG(5, lockingrange, 5) + TESTARG(6, lockingrange, 6) + TESTARG(7, lockingrange, 7) + TESTARG(8, lockingrange, 8) + TESTARG(9, lockingrange, 9) + TESTARG(10, lockingrange, 10) + TESTARG(11, lockingrange, 11) + TESTARG(12, lockingrange, 12) + TESTARG(13, lockingrange, 13) + TESTARG(14, lockingrange, 14) + TESTARG(15, lockingrange, 15) + TESTFAIL("Invalid Locking Range (0-15)") + OPTION_IS(lrstart) + OPTION_IS(lrlength) + OPTION_IS(password) + OPTION_IS(device) + END_OPTION + BEGIN_OPTION(setupLockingRange_SUM, 5) + TESTARG(0, lockingrange, 0) + TESTARG(1, lockingrange, 1) + TESTARG(2, lockingrange, 2) + TESTARG(3, lockingrange, 3) + TESTARG(4, lockingrange, 4) + TESTARG(5, lockingrange, 5) + TESTARG(6, lockingrange, 6) + TESTARG(7, lockingrange, 7) + TESTARG(8, lockingrange, 8) + TESTARG(9, lockingrange, 9) + TESTARG(10, lockingrange, 10) + TESTARG(11, lockingrange, 11) + TESTARG(12, lockingrange, 12) + TESTARG(13, lockingrange, 13) + TESTARG(14, lockingrange, 14) + TESTARG(15, lockingrange, 15) + TESTFAIL("Invalid Locking Range (0-15)") + OPTION_IS(lrstart) + OPTION_IS(lrlength) + OPTION_IS(password) + OPTION_IS(device) + END_OPTION + BEGIN_OPTION(readonlyLockingRange, 3) + TESTARG(0, lockingrange, 0) + TESTARG(1, lockingrange, 1) + TESTARG(2, lockingrange, 2) + TESTARG(3, lockingrange, 3) + TESTARG(4, lockingrange, 4) + TESTARG(5, lockingrange, 5) + TESTARG(6, lockingrange, 6) + TESTARG(7, lockingrange, 7) + TESTARG(8, lockingrange, 8) + TESTARG(9, lockingrange, 9) + TESTARG(10, lockingrange, 10) + TESTARG(11, lockingrange, 11) + TESTARG(12, lockingrange, 12) + TESTARG(13, lockingrange, 13) + TESTARG(14, lockingrange, 14) + TESTARG(15, lockingrange, 15) + TESTFAIL("Invalid Locking Range (0-15)") + OPTION_IS(password) + OPTION_IS(device) + END_OPTION + BEGIN_OPTION(listLockingRanges, 2) + OPTION_IS(password) + OPTION_IS(device) + END_OPTION + BEGIN_OPTION(listLockingRange, 3) + TESTARG(0, lockingrange, 0) + TESTARG(1, lockingrange, 1) + TESTARG(2, lockingrange, 2) + TESTARG(3, lockingrange, 3) + TESTARG(4, lockingrange, 4) + TESTARG(5, lockingrange, 5) + TESTARG(6, lockingrange, 6) + TESTARG(7, lockingrange, 7) + TESTARG(8, lockingrange, 8) + TESTARG(9, lockingrange, 9) + TESTARG(10, lockingrange, 10) + TESTARG(11, lockingrange, 11) + TESTARG(12, lockingrange, 12) + TESTARG(13, lockingrange, 13) + TESTARG(14, lockingrange, 14) + TESTARG(15, lockingrange, 15) + TESTFAIL("Invalid Locking Range (0-15)") + OPTION_IS(password) + OPTION_IS(device) + END_OPTION + BEGIN_OPTION(rekeyLockingRange, 3) + TESTARG(0, lockingrange, 0) + TESTARG(1, lockingrange, 1) + TESTARG(2, lockingrange, 2) + TESTARG(3, lockingrange, 3) + TESTARG(4, lockingrange, 4) + TESTARG(5, lockingrange, 5) + TESTARG(6, lockingrange, 6) + TESTARG(7, lockingrange, 7) + TESTARG(8, lockingrange, 8) + TESTARG(9, lockingrange, 9) + TESTARG(10, lockingrange, 10) + TESTARG(11, lockingrange, 11) + TESTARG(12, lockingrange, 12) + TESTARG(13, lockingrange, 13) + TESTARG(14, lockingrange, 14) + TESTARG(15, lockingrange, 15) + TESTFAIL("Invalid Locking Range (0-15)") + OPTION_IS(password) + OPTION_IS(device) + END_OPTION + BEGIN_OPTION(setBandsEnabled, 2) + OPTION_IS(password) + OPTION_IS(device) + END_OPTION + BEGIN_OPTION(setBandEnabled, 3) + TESTARG(0, lockingrange, 0) + TESTARG(1, lockingrange, 1) + TESTARG(2, lockingrange, 2) + TESTARG(3, lockingrange, 3) + TESTARG(4, lockingrange, 4) + TESTARG(5, lockingrange, 5) + TESTARG(6, lockingrange, 6) + TESTARG(7, lockingrange, 7) + TESTARG(8, lockingrange, 8) + TESTARG(9, lockingrange, 9) + TESTARG(10, lockingrange, 10) + TESTARG(11, lockingrange, 11) + TESTARG(12, lockingrange, 12) + TESTARG(13, lockingrange, 13) + TESTARG(14, lockingrange, 14) + TESTARG(15, lockingrange, 15) + TESTFAIL("Invalid Locking Range (0-15)") + OPTION_IS(password) + OPTION_IS(device) + END_OPTION + BEGIN_OPTION(objDump, 5) i += 4; OPTION_IS(device) END_OPTION + BEGIN_OPTION(printDefaultPassword, 1) OPTION_IS(device) END_OPTION + BEGIN_OPTION(rawCmd, 7) i += 6; OPTION_IS(device) END_OPTION + BEGIN_OPTION(readDataStore,3) OPTION_IS(filename) OPTION_IS(password) OPTION_IS(device) END_OPTION + BEGIN_OPTION(writeDataStore,3) OPTION_IS(filename) OPTION_IS(password) OPTION_IS(device) END_OPTION + else { + LOG(E) << "Invalid command line argument " << argv[i]; + return DTAERROR_INVALID_COMMAND; + } + } + return 0; +} diff --git a/sedutil-master/Common/DtaOptions.h b/sedutil-master/Common/DtaOptions.h new file mode 100644 index 0000000..c688e6b --- /dev/null +++ b/sedutil-master/Common/DtaOptions.h @@ -0,0 +1,134 @@ +/* C:B************************************************************************** +This software is Copyright 2014-2017 Bright Plaza Inc. + +This file is part of sedutil. + +sedutil is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +sedutil is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with sedutil. If not, see . + +* C:E********************************************************************** */ + +#ifndef _DTAOPTIONS_H +#define _DTAOPTIONS_H + +/** Output modes */ +typedef enum _sedutiloutput { + sedutilNormal, + sedutilReadable, + sedutilJSON +} sedutiloutput; + +/** Structure representing the command line issued to the program */ +typedef struct _DTA_OPTIONS { + uint8_t password; /**< password supplied */ + uint8_t userid; /**< userid supplied */ + uint8_t newpassword; /**< new password for password change */ + uint8_t pbafile; /**< file name for loadPBAimage command */ + uint8_t filename; /**< file name for datastore commands */ + uint8_t device; /**< device name */ + uint8_t action; /**< option requested */ + uint8_t mbrstate; /**< mbrstate for set mbr commands */ + uint8_t lockingrange; /**< locking range to be manipulated */ + uint8_t lockingstate; /**< locking state to set a lockingrange to */ + uint8_t lrstart; /** the starting block of a lockingrange */ + uint8_t lrlength; /** the length in blocks of a lockingrange */ + + bool no_hash_passwords; /** global parameter, disables hashing of passwords */ + sedutiloutput output_format; +} DTA_OPTIONS; +/** Print a usage message */ +void usage(); +/** Parse the command line and return a structure that describes the action desired + * @param argc program argc parameter + * @param argv program argv paramater + * @param opts pointer to options structure to be filled out + */ +uint8_t DtaOptions(int argc, char * argv[], DTA_OPTIONS * opts); +/** Command line options implemented in sedutil */ +typedef enum _sedutiloption { + deadbeef, // 0 should indicate no action specified + initialSetup, + setSIDPassword, + setup_SUM, + setAdmin1Pwd, + setPassword, + setPassword_SUM, + loadPBAimage, + setLockingRange, + revertTPer, + revertNoErase, + setLockingRange_SUM, + revertLockingSP, + PSIDrevert, + PSIDrevertAdminSP, + yesIreallywanttoERASEALLmydatausingthePSID, + enableLockingRange, + disableLockingRange, + readonlyLockingRange, + setupLockingRange, + setupLockingRange_SUM, + listLockingRanges, + listLockingRange, + rekeyLockingRange, + setBandsEnabled, + setBandEnabled, + setMBREnable, + setMBRDone, + enableuser, + activateLockingSP, + activateLockingSP_SUM, + eraseLockingRange_SUM, + query, + scan, + isValidSED, + eraseLockingRange, + takeOwnership, + validatePBKDF2, + objDump, + printDefaultPassword, + rawCmd, + readDataStore, + writeDataStore, + +} sedutiloption; +/** verify the number of arguments passed */ +#define CHECKARGS(x) \ +if((x+baseOptions) != argc) { \ + LOG(E) << "Incorrect number of paramaters for " << argv[i] << " command"; \ + return 100; \ + } +/** Test the command input for a recognized argument */ +#define BEGIN_OPTION(cmdstring,args) \ + else if (!(strcasecmp(#cmdstring, &argv[i][2]))) { \ + CHECKARGS(args) \ + opts->action = sedutiloption::cmdstring; \ + +/** end of an OPTION */ +#define END_OPTION } +/** test an argument for a value */ +#define TESTARG(literal,structfield,value) \ + if (!(strcasecmp(#literal, argv[i + 1]))) \ + {opts->structfield = value;} else +/** if all testargs fail then do this */ +#define TESTFAIL(msg) \ + { \ + LOG(E) << msg << " " << argv[i+1]; \ + return 1;\ + } \ +i++; + +/** set the argc value for this parameter in the options structure */ +#define OPTION_IS(option_field) \ + opts->option_field = ++i; + +#endif /* _DTAOPTIONS_H */ diff --git a/sedutil-master/Common/DtaResponse.cpp b/sedutil-master/Common/DtaResponse.cpp new file mode 100644 index 0000000..83cecde --- /dev/null +++ b/sedutil-master/Common/DtaResponse.cpp @@ -0,0 +1,252 @@ +/* C:B************************************************************************** +This software is Copyright 2014-2017 Bright Plaza Inc. + +This file is part of sedutil. + +sedutil is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +sedutil is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with sedutil. If not, see . + + * C:E********************************************************************** */ +#include "os.h" +#include "DtaResponse.h" +#include "DtaEndianFixup.h" +using namespace std; + +DtaResponse::DtaResponse() +{ + LOG(D1) << "Creating DtaResponse()"; +} + +DtaResponse::DtaResponse(void * buffer) +{ + LOG(D1) << "Creating DtaResponse(buffer)"; + init(buffer); +} + +void +DtaResponse::init(void * buffer) +{ + LOG(D1) << "Entering DtaResponse::init"; + std::vector bytestring, empty_atom(1, 0xff); + uint8_t * reply = (uint8_t *) buffer; + uint32_t cpos = 0; + uint32_t tokenLength; + memcpy(&h, buffer, sizeof (OPALHeader)); + response.clear(); + reply += sizeof (OPALHeader); + while (cpos < SWAP32(h.subpkt.length)) { + bytestring.clear(); + if (!(reply[cpos] & 0x80)) //tiny atom + tokenLength = 1; + else if (!(reply[cpos] & 0x40)) // short atom + tokenLength = (reply[cpos] & 0x0f) + 1; + else if (!(reply[cpos] & 0x20)) // medium atom + tokenLength = (((reply[cpos] & 0x07) << 8) | reply[cpos + 1]) + 2; + else if (!(reply[cpos] & 0x10)) // long atom + tokenLength = ((reply[cpos + 1] << 16) | (reply[cpos + 2] << 8) | reply[cpos + 3]) + 4; + else // TOKEN + tokenLength = 1; + + for (uint32_t i = 0; i < tokenLength; i++) { + bytestring.push_back(reply[cpos++]); + } + if (bytestring != empty_atom) + response.push_back(bytestring); + } +} + +OPAL_TOKEN DtaResponse::tokenIs(uint32_t tokenNum) +{ + LOG(D1) << "Entering DtaResponse::tokenIs"; + if (!(response[tokenNum][0] & 0x80)) { //tiny atom + if ((response[tokenNum][0] & 0x40)) + return OPAL_TOKEN::DTA_TOKENID_SINT; + else + return OPAL_TOKEN::DTA_TOKENID_UINT; + } + else if (!(response[tokenNum][0] & 0x40)) { // short atom + if ((response[tokenNum][0] & 0x20)) + return OPAL_TOKEN::DTA_TOKENID_BYTESTRING; + else if ((response[tokenNum][0] & 0x10)) + return OPAL_TOKEN::DTA_TOKENID_SINT; + else + return OPAL_TOKEN::DTA_TOKENID_UINT; + } + else if (!(response[tokenNum][0] & 0x20)) { // medium atom + if ((response[tokenNum][0] & 0x10)) + return OPAL_TOKEN::DTA_TOKENID_BYTESTRING; + else if ((response[tokenNum][0] & 0x08)) + return OPAL_TOKEN::DTA_TOKENID_SINT; + else + return OPAL_TOKEN::DTA_TOKENID_UINT; + } + else if (!(response[tokenNum][0] & 0x10)) { // long atom + if ((response[tokenNum][0] & 0x02)) + return OPAL_TOKEN::DTA_TOKENID_BYTESTRING; + else if ((response[tokenNum][0] & 0x01)) + return OPAL_TOKEN::DTA_TOKENID_SINT; + else + return OPAL_TOKEN::DTA_TOKENID_UINT; + } + else // TOKEN + return (OPAL_TOKEN) response[tokenNum][0]; +} + +uint32_t DtaResponse::getLength(uint32_t tokenNum) +{ + return (uint32_t) response[tokenNum].size(); +} + +uint64_t DtaResponse::getUint64(uint32_t tokenNum) +{ + LOG(D1) << "Entering DtaResponse::getUint64"; + if (!(response[tokenNum][0] & 0x80)) { //tiny atom + if ((response[tokenNum][0] & 0x40)) { + LOG(E) << "unsigned int requested for signed tiny atom"; + exit(EXIT_FAILURE); + } + else { + return (uint64_t) (response[tokenNum][0] & 0x3f); + } + } + else if (!(response[tokenNum][0] & 0x40)) { // short atom + if ((response[tokenNum][0] & 0x10)) { + LOG(E) << "unsigned int requested for signed short atom"; + exit(EXIT_FAILURE); + } + else { + uint64_t whatever = 0; + if (response[tokenNum].size() > 9) { LOG(E) << "UINT64 with greater than 8 bytes"; } + int b = 0; + for (uint32_t i = (uint32_t) response[tokenNum].size() - 1; i > 0; i--) { + whatever |= ((uint64_t)response[tokenNum][i] << (8 * b)); + b++; + } + return whatever; + } + + } + else if (!(response[tokenNum][0] & 0x20)) { // medium atom + LOG(E) << "unsigned int requested for medium atom is unsupported"; + exit(EXIT_FAILURE); + } + else if (!(response[tokenNum][0] & 0x10)) { // long atom + LOG(E) << "unsigned int requested for long atom is unsupported"; + exit(EXIT_FAILURE); + } + else { // TOKEN + LOG(E) << "unsigned int requested for token is unsupported"; + exit(EXIT_FAILURE); + } + +} + +uint32_t DtaResponse::getUint32(uint32_t tokenNum) +{ + LOG(D1) << "Entering DtaResponse::getUint32"; + uint64_t i = getUint64(tokenNum); + if (i > 0xffffffff) { LOG(E) << "UINT32 truncated "; } + return (uint32_t) i; + +} + +uint16_t DtaResponse::getUint16(uint32_t tokenNum) +{ + LOG(D1) << "Entering DtaResponse::getUint16"; + uint64_t i = getUint64(tokenNum); + if (i > 0xffff) { LOG(E) << "UINT16 truncated "; } + return (uint16_t) i; +} + +uint8_t DtaResponse::getUint8(uint32_t tokenNum) +{ + LOG(D1) << "Entering DtaResponse::getUint8"; + uint64_t i = getUint64(tokenNum); + if (i > 0xff) { LOG(E) << "UINT8 truncated "; } + return (uint8_t) i; +} +//int64_t DtaResponse::getSint(uint32_t tokenNum) { +// LOG(E) << "DtaResponse::getSint() is not implemented"; +//} + +std::vector DtaResponse::getRawToken(uint32_t tokenNum) +{ + return response[tokenNum]; +} + +std::string DtaResponse::getString(uint32_t tokenNum) +{ + LOG(D1) << "Entering DtaResponse::getString"; + std::string s; + s.erase(); + int overhead = 0; + if (!(response[tokenNum][0] & 0x80)) { //tiny atom + LOG(E) << "Cannot get a string from a tiny atom"; + exit(EXIT_FAILURE); + } + else if (!(response[tokenNum][0] & 0x40)) { // short atom + overhead = 1; + } + else if (!(response[tokenNum][0] & 0x20)) { // medium atom + overhead = 2; + } + else if (!(response[tokenNum][0] & 0x10)) { // long atom + overhead = 4; + } + else { + LOG(E) << "Cannot get a string from a TOKEN"; + return s; + } + for (uint32_t i = overhead; i < response[tokenNum].size(); i++) { + s.push_back(response[tokenNum][i]); + } + return s; +} + +void DtaResponse::getBytes(uint32_t tokenNum, uint8_t bytearray[]) +{ + LOG(D1) << "Entering DtaResponse::getBytes"; + int overhead = 0; + if (!(response[tokenNum][0] & 0x80)) { //tiny atom + LOG(E) << "Cannot get a bytestring from a tiny atom"; + exit(EXIT_FAILURE); + } + else if (!(response[tokenNum][0] & 0x40)) { // short atom + overhead = 1; + } + else if (!(response[tokenNum][0] & 0x20)) { // medium atom + overhead = 2; + } + else if (!(response[tokenNum][0] & 0x10)) { // long atom + overhead = 4; + } + else { + LOG(E) << "Cannot get a bytestring from a TOKEN"; + exit(EXIT_FAILURE); + } + + for (uint32_t i = overhead; i < response[tokenNum].size(); i++) { + bytearray[i - overhead] = response[tokenNum][i]; + } +} + +uint32_t DtaResponse::getTokenCount() +{ + LOG(D1) << "Entering DtaResponse::getTokenCount()"; + return (uint32_t) response.size(); +} + +DtaResponse::~DtaResponse() +{ + LOG(D1) << "Destroying DtaResponse"; +} diff --git a/sedutil-master/Common/DtaResponse.h b/sedutil-master/Common/DtaResponse.h new file mode 100644 index 0000000..393d656 --- /dev/null +++ b/sedutil-master/Common/DtaResponse.h @@ -0,0 +1,80 @@ +/* C:B************************************************************************** +This software is Copyright 2014-2017 Bright Plaza Inc. + +This file is part of sedutil. + +sedutil is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +sedutil is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with sedutil. If not, see . + + * C:E********************************************************************** */ +#pragma once +#include +#include +#include "DtaStructures.h" +#include "DtaLexicon.h" + + +/** Object containing the parsed tokens. + * a vector of vector that contains each token + * returned in the TCG response + */ +class DtaResponse { +public: + DtaResponse(); + /** constructor + * @param buffer the response returned by a TCG command */ + DtaResponse(void * buffer); + ~DtaResponse(); + /** (re)initialize the object using a new buffer + * @param buffer the response returned by a TCG command */ + void init(void * buffer); + /** return the type of token + * @param tokenNum the 0 based number of the token*/ + OPAL_TOKEN tokenIs(uint32_t tokenNum); + /** return the length of a token + * @param tokenNum the 0 based number of the token*/ + uint32_t getLength(uint32_t tokenNum); + /** return an unsigned 64bit integer + * @param tokenNum the 0 based number of the token*/ + uint64_t getUint64(uint32_t tokenNum); + /** return an unsigned 32bit integer + * @param tokenNum the 0 based number of the token*/ + uint32_t getUint32(uint32_t tokenNum); + /** return an unsigned 16bit integer + * @param tokenNum the 0 based number of the token*/ + uint16_t getUint16(uint32_t tokenNum); + /** return an unsigned 8bit integer + * @param tokenNum the 0 based number of the token*/ + uint8_t getUint8(uint32_t tokenNum); + /** return the number of tokens in the response */ + uint32_t getTokenCount(); + /** return a string of the token + * @param tokenNum the 0 based number of the token*/ + std::string getString(uint32_t tokenNum); + /** return the entire token including TCG token overhead + * @param tokenNum the 0 based number of the token*/ + std::vector getRawToken(uint32_t tokenNum); + /** return the token in an array of uint8_t + * @param tokenNum the 0 based number of the token + * @param bytearray pointer to array for return data */ + void getBytes(uint32_t tokenNum, uint8_t bytearray[]); + + OPALHeader h; /**< TCG Header fields of the response */ + +private: + + std::vector> response; /**< tokenized resonse */ +}; + + + diff --git a/sedutil-master/Common/DtaSession.cpp b/sedutil-master/Common/DtaSession.cpp new file mode 100644 index 0000000..e7b51a1 --- /dev/null +++ b/sedutil-master/Common/DtaSession.cpp @@ -0,0 +1,334 @@ +/* C:B************************************************************************** +This software is Copyright 2014-2017 Bright Plaza Inc. + +This file is part of sedutil. + +sedutil is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +sedutil is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with sedutil. If not, see . + + * C:E********************************************************************** */ +#include "os.h" +#include +#include "DtaSession.h" +#include "DtaOptions.h" +#include "DtaDev.h" +#include "DtaCommand.h" +#include "DtaResponse.h" +#include "DtaEndianFixup.h" +#include "DtaHexDump.h" +#include "DtaHashPwd.h" +#include "DtaStructures.h" + +using namespace std; + +DtaSession::DtaSession(DtaDev * device) +{ + LOG(D1) << "Creating DtaSsession()"; + sessionauth = 0; + d = device; +} + +uint8_t +DtaSession::start(OPAL_UID SP) +{ + return (start(SP, NULL, OPAL_UID::OPAL_UID_HEXFF)); +} + +uint8_t +DtaSession::start(OPAL_UID SP, char * HostChallenge, OPAL_UID SignAuthority) +{ + LOG(D1) << "Entering DtaSession::startSession "; + vector auth; + auth.push_back(OPAL_SHORT_ATOM::BYTESTRING8); + for (int i = 0; i < 8; i++) { + auth.push_back(OPALUID[SignAuthority][i]); + } + return(start(SP, HostChallenge, auth)); +} +uint8_t DtaSession::authuser() { + return sessionauth; +} +#ifdef MULTISTART +uint8_t +DtaSession::start(OPAL_UID SP, char * HostChallenge, vector SignAuthority) +{ + vector auth; + if ((lastRC = unistart(SP, HostChallenge, SignAuthority)) == 0) { + sessionauth = 0; + return 0; + } + else { + for (uint8_t i = 1; i < 9; i++) { + // { 0x00, 0x00, 0x00, 0x09, 0x00, 0x03, 0x00, 0x01 }, /**< USER1 */ + auth.clear(); + auth.push_back(OPAL_SHORT_ATOM::BYTESTRING8); + auth.push_back(0x00); + auth.push_back(0x00); + auth.push_back(0x00); + auth.push_back(0x09); + auth.push_back(0x00); + auth.push_back(0x03); + auth.push_back(0x00); + auth.push_back(i); + if ((lastRC = unistart(SP, HostChallenge, auth)) == 0) { + sessionauth = i; + return 0; + } + } + + } + return lastRC; +} +uint8_t +DtaSession::unistart(OPAL_UID SP, char * HostChallenge, vector SignAuthority) +#else +uint8_t +DtaSession::start(OPAL_UID SP, char * HostChallenge, vector SignAuthority) +#endif +{ + LOG(D1) << "Entering DtaSession::startSession "; + vector hash; + lastRC = 0; + + DtaCommand *cmd = new DtaCommand(); + if (NULL == cmd) { + LOG(E) << "Unable to create session object "; + return DTAERROR_OBJECT_CREATE_FAILED; + } + DtaResponse response; + cmd->reset(OPAL_UID::OPAL_SMUID_UID, OPAL_METHOD::STARTSESSION); + cmd->addToken(OPAL_TOKEN::STARTLIST); // [ (Open Bracket) + cmd->addToken(105); // HostSessionID : sessionnumber + cmd->addToken(SP); // SPID : SP + cmd->addToken(OPAL_TINY_ATOM::UINT_01); // write + if ((NULL != HostChallenge) && (!d->isEprise())) { + cmd->addToken(OPAL_TOKEN::STARTNAME); + cmd->addToken(OPAL_TINY_ATOM::UINT_00); + if (hashPwd) { + hash.clear(); + DtaHashPwd(hash, HostChallenge, d); + cmd->addToken(hash); + } else { + cmd->addToken(HostChallenge); + } + cmd->addToken(OPAL_TOKEN::ENDNAME); + cmd->addToken(OPAL_TOKEN::STARTNAME); + cmd->addToken(OPAL_TINY_ATOM::UINT_03); + cmd->addToken(SignAuthority); + cmd->addToken(OPAL_TOKEN::ENDNAME); + } + + // w/o the timeout the session may wedge and require a power-cycle, + // e.g., when interrupted by ^C. 60 seconds is inconveniently long, + // but revert may require that long to complete. + if (d->isEprise()) { + cmd->addToken(OPAL_TOKEN::STARTNAME); + cmd->addToken("SessionTimeout"); + cmd->addToken(60000); + cmd->addToken(OPAL_TOKEN::ENDNAME); + } + + cmd->addToken(OPAL_TOKEN::ENDLIST); // ] (Close Bracket) + cmd->complete(); + if ((lastRC = sendCommand(cmd, response)) != 0) { + LOG(E) << "Session start failed rc = " << (int)lastRC; + delete cmd; + return lastRC; + } + // call user method SL HSN TSN EL EOD SL 00 00 00 EL + // 0 1 2 3 4 5 6 7 8 + HSN = SWAP32(response.getUint32(4)); + TSN = SWAP32(response.getUint32(5)); + delete cmd; + if ((NULL != HostChallenge) && (d->isEprise())) { + return(authenticate(SignAuthority, HostChallenge)); + } + return 0; +} +uint8_t +DtaSession::authenticate(vector Authority, char * Challenge) +{ + LOG(D1) << "Entering DtaSession::authenticate "; + vector hash; + DtaCommand *cmd = new DtaCommand(); + if (NULL == cmd) { + LOG(E) << "Unable to create session object "; + return DTAERROR_OBJECT_CREATE_FAILED; + } + DtaResponse response; + cmd->reset(OPAL_UID::OPAL_THISSP_UID, d->isEprise() ? OPAL_METHOD::EAUTHENTICATE : OPAL_METHOD::AUTHENTICATE); + cmd->addToken(OPAL_TOKEN::STARTLIST); // [ (Open Bracket) + cmd->addToken(Authority); + if (Challenge && *Challenge) + { + cmd->addToken(OPAL_TOKEN::STARTNAME); + if (d->isEprise()) + cmd->addToken("Challenge"); + else + cmd->addToken(OPAL_TINY_ATOM::UINT_00); + if (hashPwd) { + hash.clear(); + DtaHashPwd(hash, Challenge, d); + cmd->addToken(hash); + } + else + cmd->addToken(Challenge); + cmd->addToken(OPAL_TOKEN::ENDNAME); + } + cmd->addToken(OPAL_TOKEN::ENDLIST); // ] (Close Bracket) + cmd->complete(); + if ((lastRC = sendCommand(cmd, response)) != 0) { + LOG(E) << "Session Authenticate failed"; + delete cmd; + return lastRC; + } + if (0 == response.getUint8(1)) { + LOG(E) << "Session Authenticate failed (response = false)"; + delete cmd; + return DTAERROR_AUTH_FAILED; + } + + LOG(D1) << "Exiting DtaSession::authenticate "; + delete cmd; + return 0; +} +uint8_t +DtaSession::sendCommand(DtaCommand * cmd, DtaResponse & response) +{ + LOG(D1) << "Entering DtaSession::sendCommand()"; + cmd->setHSN(HSN); + cmd->setTSN(TSN); + cmd->setcomID(d->comID()); + + uint8_t exec_rc = d->exec(cmd, response, SecurityProtocol); + if (0 != exec_rc) + { + LOG(E) << "Command failed on exec " << (uint16_t) exec_rc; + return exec_rc; + } + /* + * Check out the basics that so that we know we + * have a sane reply to work with + */ + // zero lengths -- these are big endian but it doesn't matter for uint = 0 + if ((0 == response.h.cp.length) || + (0 == response.h.pkt.length) || + (0 == response.h.subpkt.length)) { + LOG(E) << "One or more header fields have 0 length"; + return DTAERROR_COMMAND_ERROR; + } + // if we get an endsession response return 0 + if (OPAL_TOKEN::ENDOFSESSION == response.tokenIs(0)) { + return 0; + } + // IF we received a method status return it + if (!((OPAL_TOKEN::ENDLIST == response.tokenIs(response.getTokenCount() - 1)) && + (OPAL_TOKEN::STARTLIST == response.tokenIs(response.getTokenCount() - 5)))) { + // no method status so we hope we reported the error someplace else + LOG(E) << "Method Status missing"; + return DTAERROR_NO_METHOD_STATUS; + } + if (OPALSTATUSCODE::SUCCESS != response.getUint8(response.getTokenCount() - 4)) { + LOG(E) << "method status code " << + methodStatus(response.getUint8(response.getTokenCount() - 4)); + } + return response.getUint8(response.getTokenCount() - 4); +} + +void +DtaSession::setProtocol(uint8_t value) +{ + LOG(D1) << "Entering DtaSession::setProtocol"; + SecurityProtocol = value; +} + +void +DtaSession::dontHashPwd() +{ + LOG(D1) << "Entering DtaSession::setProtocol"; + hashPwd = 0; +} + +void +DtaSession::expectAbort() +{ + LOG(D1) << "Entering DtaSession::methodStatus()"; + willAbort = 1; +} + +char * +DtaSession::methodStatus(uint8_t status) +{ + LOG(D1) << "Entering DtaSession::methodStatus()"; + switch (status) { + case OPALSTATUSCODE::AUTHORITY_LOCKED_OUT: + return (char *) "AUTHORITY_LOCKED_OUT"; + case OPALSTATUSCODE::FAIL: + return (char *) "FAIL"; + case OPALSTATUSCODE::INSUFFICIENT_ROWS: + return (char *) "INSUFFICIENT_ROWS"; + case OPALSTATUSCODE::INSUFFICIENT_SPACE: + return (char *) "INSUFFICIENT_SPACE"; + case OPALSTATUSCODE::INVALID_FUNCTION: + return (char *) "INVALID_FUNCTION"; + case OPALSTATUSCODE::INVALID_PARAMETER: + return (char *) "INVALID_PARAMETER"; + case OPALSTATUSCODE::INVALID_REFERENCE: + return (char *) "INVALID_REFERENCE"; + case OPALSTATUSCODE::NOT_AUTHORIZED: + return (char *) "NOT_AUTHORIZED"; + case OPALSTATUSCODE::NO_SESSIONS_AVAILABLE: + return (char *) "NO_SESSIONS_AVAILABLE"; + case OPALSTATUSCODE::RESPONSE_OVERFLOW: + return (char *) "RESPONSE_OVERFLOW"; + case OPALSTATUSCODE::SP_BUSY: + return (char *) "SP_BUSY"; + case OPALSTATUSCODE::SP_DISABLED: + return (char *) "SP_DISABLED"; + case OPALSTATUSCODE::SP_FAILED: + return (char *) "SP_FAILED"; + case OPALSTATUSCODE::SP_FROZEN: + return (char *) "SP_FROZEN"; + case OPALSTATUSCODE::SUCCESS: + return (char *) "SUCCESS"; + case OPALSTATUSCODE::TPER_MALFUNCTION: + return (char *) "TPER_MALFUNCTION"; + case OPALSTATUSCODE::TRANSACTION_FAILURE: + return (char *) "TRANSACTION_FAILURE"; + case OPALSTATUSCODE::UNIQUENESS_CONFLICT: + return (char *) "UNIQUENESS_CONFLICT"; + default: + return (char *) "Unknown status code"; + } +} + +DtaSession::~DtaSession() +{ + LOG(D1) << "Destroying DtaSession"; + DtaResponse response; + if (!willAbort) { + DtaCommand *cmd = new DtaCommand(); + if (NULL == cmd) { + LOG(E) << "Unable to create command object "; + } + else { + cmd->reset(); + cmd->addToken(OPAL_TOKEN::ENDOFSESSION); + cmd->complete(0); + if (sendCommand(cmd, response)) { + LOG(E) << "EndSession Failed"; + } + delete cmd; + } + } +} diff --git a/sedutil-master/Common/DtaSession.h b/sedutil-master/Common/DtaSession.h new file mode 100644 index 0000000..bd8953b --- /dev/null +++ b/sedutil-master/Common/DtaSession.h @@ -0,0 +1,106 @@ +/* C:B************************************************************************** +This software is Copyright 2014-2017 Bright Plaza Inc. + +This file is part of sedutil. + +sedutil is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +sedutil is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with sedutil. If not, see . + +* C:E********************************************************************** */ +#pragma once +/* + * Manage tDtaLexicon + */ +#include "DtaLexicon.h" +#include +class DtaCommand; +class DtaDev; +class DtaResponse; + +using namespace std; +/** Encapsulate the session management functionality */ +class DtaSession { +public: + /** Constructor + * @param device the device the session is to be conducted with + */ + DtaSession(DtaDev * device); + /** Destructor ends the session if required */ + ~DtaSession(); + /** start an anonymous session + * @param SP the Security Provider to start the session with */ + uint8_t start(OPAL_UID SP); + /** Start an authenticated session with any user(1-8) or admint (OPAL only) + * @param SP the securitly provider to start the session with + * @param HostChallenge the password to start the session + * @param SignAuthority the Signing authority (in a simple session this is the user) + * */ +#ifdef MULTISTART + uint8_t unistart(OPAL_UID SP, char * HostChallenge, vector SignAuthority); +#endif + /** Start an authenticated session (OPAL only) + * @param SP the securitly provider to start the session with + * @param HostChallenge the password to start the session + * @param SignAuthority the Signing authority (in a simple session this is the user) + */ + uint8_t start(OPAL_UID SP, char * HostChallenge, OPAL_UID SignAuthority); + /** Start an authenticated session (OPAL only) + * @param SP the securitly provider to start the session with + * @param HostChallenge the password to start the session + * @param SignAuthority the Signing authority (in a simple session this is the user) + * */ + uint8_t start(OPAL_UID SP, char * HostChallenge, vector SignAuthority); + /** Authenticate an already started session + * @param Authority the authority to authenticate + * @param Challenge the password + */ + uint8_t authenticate(vector Authority, char * Challenge); + /** assign the security protocol to be used in the sessiion + * @param value the security protocol number + */ + void setProtocol(uint8_t value); + /** The password is not to be hashed. + * This is used when the factory default password or the PSID password is + * used to authenticate a session + */ + void dontHashPwd(); + /** expect the session to abort. + * this is used when the method called will abort the session (revert) + * to suppress the normal error checking + */ + void expectAbort(); + /** return the authorization the session has started under */ + uint8_t authuser(); + /** send a command to the device in this session + * @param cmd The DtaCommand object + * @param response The MesdResponse object + */ + uint8_t sendCommand(DtaCommand * cmd, DtaResponse & response); +private: + /** Default constructor, private should never be called */ + DtaSession(); + /** return a string explaining the method status + * @param status the method status code returned + */ + char * methodStatus(uint8_t status); + DtaDev * d; /**< Pointer to device this session is with */ + uint32_t bufferpos = 0; /**< psooition in the response buffer the parser is at */ + uint32_t TSN = 0; /**< TPer session number */ + uint32_t HSN = 0; /**< Host session number */ + uint8_t willAbort = 0; /**< Command is expected to abort */ + uint8_t hashPwd = 1; /**< hash the password when authenticating */ + uint8_t SecurityProtocol = 0x01; /**< The seurity protocol to be used */ + uint8_t lastRC; /**< last return code */ + uint8_t sessionauth; /** authid for multistart */ +}; + diff --git a/sedutil-master/Common/DtaStructures.h b/sedutil-master/Common/DtaStructures.h new file mode 100644 index 0000000..12a92b0 --- /dev/null +++ b/sedutil-master/Common/DtaStructures.h @@ -0,0 +1,469 @@ +/* C:B************************************************************************** +This software is Copyright 2014-2017 Bright Plaza Inc. + +This file is part of sedutil. + +sedutil is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +sedutil is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with sedutil. If not, see . + + * C:E********************************************************************** */ +#pragma once +#pragma pack(push) +#pragma pack(1) + +#define FC_TPER 0x0001 +#define FC_LOCKING 0x0002 +#define FC_GEOMETRY 0x0003 +#define FC_ENTERPRISE 0x0100 +#define FC_DATASTORE 0x0202 +#define FC_SINGLEUSER 0x0201 +#define FC_OPALV100 0x0200 +#define FC_OPALV200 0x0203 +/** The Discovery 0 Header. As defined in +* Opal SSC Documentation +*/ +typedef struct _Discovery0Header { + uint32_t length; /**< the lenght of the header 48 in 2.00.100*/ + uint32_t revision; /**< revision of the header 1 in 2.00.100 */ + uint32_t reserved01; + uint32_t reserved02; + // the remainder of the structure is vendor specific and will not be addressed now +} Discovery0Header; + +/** TPer Feature Descriptor. Contains flags indicating support for the + * TPer features described in the OPAL specification. The names match the + * OPAL terminology + */ +typedef struct _Discovery0TPerFeatures { + uint16_t featureCode; /* 0x0001 in 2.00.100 */ + uint8_t reserved_v : 4; + uint8_t version : 4; + uint8_t length; + /* big endian + uint8_t reserved01 : 1; + uint8_t comIDManagement : 1; + uint8_t reserved02 : 1; + uint8_t streaming : 1; + uint8_t bufferManagement : 1; + uint8_t acknack : 1; + uint8_t async : 1; + uint8_t sync : 1; + */ + uint8_t sync : 1; + uint8_t async : 1; + uint8_t acknack : 1; + uint8_t bufferManagement : 1; + uint8_t streaming : 1; + uint8_t reserved02 : 1; + uint8_t comIDManagement : 1; + uint8_t reserved01 : 1; + + uint32_t reserved03; + uint32_t reserved04; + uint32_t reserved05; +} Discovery0TPerFeatures; + +/** Locking Feature Descriptor. Contains flags indicating support for the + * locking features described in the OPAL specification. The names match the + * OPAL terminology + */ +typedef struct _Discovery0LockingFeatures { + uint16_t featureCode; /* 0x0002 in 2.00.100 */ + uint8_t reserved_v : 4; + uint8_t version : 4; + uint8_t length; + /* Big endian + uint8_t reserved01 : 1; + uint8_t reserved02 : 1; + uint8_t MBRDone : 1; + uint8_t MBREnabled : 1; + uint8_t mediaEncryption : 1; + uint8_t locked : 1; + uint8_t lockingEnabled : 1; + uint8_t lockingSupported : 1; + */ + uint8_t lockingSupported : 1; + uint8_t lockingEnabled : 1; + uint8_t locked : 1; + uint8_t mediaEncryption : 1; + uint8_t MBREnabled : 1; + uint8_t MBRDone : 1; + uint8_t reserved01 : 1; + uint8_t reserved02 : 1; + + uint32_t reserved03; + uint32_t reserved04; + uint32_t reserved05; +} Discovery0LockingFeatures; + +/** Geometry Feature Descriptor. Contains flags indicating support for the + * geometry features described in the OPAL specification. The names match the + * OPAL terminology + */ +typedef struct _Discovery0GeometryFeatures { + uint16_t featureCode; /* 0x0003 in 2.00.100 */ + uint8_t reserved_v : 4; + uint8_t version : 4; + uint8_t length; + /* big Endian + uint8_t reserved01 : 7; + uint8_t align : 1; + */ + uint8_t align : 1; + uint8_t reserved01 : 7; + uint8_t reserved02[7]; + uint32_t logicalBlockSize; + uint64_t alignmentGranularity; + uint64_t lowestAlighedLBA; +} Discovery0GeometryFeatures; + +/** Enterprise SSC Feature + */ +typedef struct _Discovery0EnterpriseSSC { + uint16_t featureCode; /* 0x0100 */ + uint8_t reserved_v : 4; + uint8_t version : 4; + uint8_t length; + uint16_t baseComID; + uint16_t numberComIDs; + /* big endian + uint8_t reserved01 : 7; + uint8_t rangeCrossing : 1; + */ + uint8_t rangeCrossing : 1; + uint8_t reserved01 : 7; + + uint8_t reserved02; + uint16_t reserved03; + uint32_t reserved04; + uint32_t reserved05; +} Discovery0EnterpriseSSC; + +/** Opal V1 feature + */ +typedef struct _Discovery0OpalV100 { + uint16_t featureCode; /* 0x0200 */ + uint8_t reserved_v : 4; + uint8_t version : 4; + uint8_t length; + uint16_t baseComID; + uint16_t numberComIDs; +} Discovery0OpalV100; +/** Single User Mode feature + */ +typedef struct _Discovery0SingleUserMode { + uint16_t featureCode; /* 0x0201 */ + uint8_t reserved_v : 4; + uint8_t version : 4; + uint8_t length; + uint32_t numberLockingObjects; + /* big endian + uint8_t reserved01 : 5; + uint8_t policy : 1; + uint8_t all : 1; + uint8_t any : 1; + */ + uint8_t any : 1; + uint8_t all : 1; + uint8_t policy : 1; + uint8_t reserved01 : 5; + + uint8_t reserved02; + uint16_t reserved03; + uint32_t reserved04; +} Discovery0SingleUserMode; + +/** Additonal Datastores feature . + */ +typedef struct _Discovery0DatastoreTable { + uint16_t featureCode; /* 0x0203 */ + uint8_t reserved_v : 4; + uint8_t version : 4; + uint8_t length; + uint16_t reserved01; + uint16_t maxTables; + uint32_t maxSizeTables; + uint32_t tableSizeAlignment; +} Discovery0DatastoreTable; + +/** OPAL 2.0 feature + */ +typedef struct _Discovery0OPALV200 { + uint16_t featureCode; /* 0x0203 */ + uint8_t reserved_v : 4; + uint8_t version : 4; + uint8_t length; + uint16_t baseCommID; + uint16_t numCommIDs; + /* big endian + uint8_t reserved01 : 7; + uint8_t rangeCrossing : 1; + */ + uint8_t rangeCrossing : 1; + uint8_t reserved01 : 7; + + uint16_t numlockingAdminAuth; + uint16_t numlockingUserAuth; + uint8_t initialPIN; + uint8_t revertedPIN; + uint8_t reserved02; + uint32_t reserved03; +} Discovery0OPALV200; +/** Union of features used to parse the discovery 0 response */ +union Discovery0Features { + Discovery0TPerFeatures TPer; + Discovery0LockingFeatures locking; + Discovery0GeometryFeatures geometry; + Discovery0EnterpriseSSC enterpriseSSC; + Discovery0SingleUserMode singleUserMode; + Discovery0OPALV200 opalv200; + Discovery0OpalV100 opalv100; + Discovery0DatastoreTable datastore; +}; + +/** ComPacket (header) for transmissions. */ + +typedef struct _OPALComPacket { + uint32_t reserved0; + uint8_t extendedComID[4]; + uint32_t outstandingData; + uint32_t minTransfer; + uint32_t length; +} OPALComPacket; + +/** Packet structure. */ +typedef struct _OPALPacket { + uint32_t TSN; + uint32_t HSN; + uint32_t seqNumber; + uint16_t reserved0; + uint16_t ackType; + uint32_t acknowledgement; + uint32_t length; +} OPALPacket; + +/** Data sub packet header */ +typedef struct _OPALDataSubPacket { + uint8_t reserved0[6]; + uint16_t kind; + uint32_t length; +} OPALDataSubPacket; +/** header of a response */ +typedef struct _OPALHeader { + OPALComPacket cp; + OPALPacket pkt; + OPALDataSubPacket subpkt; +} OPALHeader; +/** ATA commands needed for TCG storage communication */ +typedef enum _ATACOMMAND { + IF_RECV = 0x5c, + IF_SEND = 0x5e, + IDENTIFY = 0xec, +} ATACOMMAND; + +typedef enum _DTA_DEVICE_TYPE { + DEVICE_TYPE_ATA, + DEVICE_TYPE_SAS, + DEVICE_TYPE_NVME, + DEVICE_TYPE_USB, + DEVICE_TYPE_OTHER, +} DTA_DEVICE_TYPE; + +/** structure to store Disk information. */ +typedef struct _OPAL_DiskInfo { + // parsed the Function block? + uint8_t Unknown; + uint8_t VendorSpecific; + uint8_t TPer : 1; + uint8_t Locking : 1; + uint8_t Geometry : 1; + uint8_t Enterprise : 1; + uint8_t SingleUser : 1; + uint8_t DataStore : 1; + uint8_t OPAL20 : 1; + uint8_t OPAL10 : 1; + uint8_t Properties : 1; + uint8_t ANY_OPAL_SSC : 1; + // values ONLY VALID IF FUNCTION ABOVE IS TRUE!!!!! + uint8_t TPer_ACKNACK : 1; + uint8_t TPer_async : 1; + uint8_t TPer_bufferMgt : 1; + uint8_t TPer_comIDMgt : 1; + uint8_t TPer_streaming : 1; + uint8_t TPer_sync : 1; + uint8_t Locking_locked : 1; + uint8_t Locking_lockingEnabled : 1; + uint8_t Locking_lockingSupported : 1; + uint8_t Locking_MBRDone : 1; + uint8_t Locking_MBREnabled : 1; + uint8_t Locking_mediaEncrypt : 1; + uint8_t Geometry_align : 1; + uint64_t Geometry_alignmentGranularity; + uint32_t Geometry_logicalBlockSize; + uint64_t Geometry_lowestAlignedLBA; + uint8_t Enterprise_rangeCrossing : 1; + uint16_t Enterprise_basecomID; + uint16_t Enterprise_numcomID; + uint8_t SingleUser_any : 1; + uint8_t SingleUser_all : 1; + uint8_t SingleUser_policy : 1; + uint32_t SingleUser_lockingObjects; + uint16_t DataStore_maxTables; + uint32_t DataStore_maxTableSize; + uint32_t DataStore_alignment; + uint16_t OPAL10_basecomID; + uint16_t OPAL10_numcomIDs; + uint16_t OPAL20_basecomID; + uint16_t OPAL20_numcomIDs; + uint8_t OPAL20_initialPIN; + uint8_t OPAL20_revertedPIN; + uint16_t OPAL20_numAdmins; + uint16_t OPAL20_numUsers; + uint8_t OPAL20_rangeCrossing; + // IDENTIFY information + DTA_DEVICE_TYPE devType; + uint8_t serialNum[20]; + uint8_t null0; // make sn a cstring + uint8_t firmwareRev[8]; + uint8_t null1; // make firmware rev a cstring + uint8_t modelNum[40]; + uint8_t null2; // make model number a cstring +} OPAL_DiskInfo; +/** Response returned by ATA Identify */ +typedef struct _IDENTIFY_RESPONSE { + uint8_t reserved0; + uint8_t reserved1 : 7; + uint8_t devType : 1; + uint8_t reserved2[18]; + uint8_t serialNum[20]; + uint8_t reserved3[6]; + uint8_t firmwareRev[8]; + uint8_t modelNum[40]; +} IDENTIFY_RESPONSE; + +typedef struct _UASP_INQUIRY_RESPONSE { + uint8_t fill1[20]; + char ProductSerial[20]; + uint8_t fill2[6]; + char ProductRev[8]; + char ProductID[40]; +} UASP_INQUIRY_RESPONSE; + +typedef struct _SCSI_INQUIRY_RESPONSE { + uint8_t fill1[16]; + char ProductID[16]; + char ProductRev[4]; +} SCSI_INQUIRY_RESPONSE; + + +//////////////////////////////////////////////////////////////////////////////// +class CScsiCmdInquiry +//////////////////////////////////////////////////////////////////////////////// +{ +public: + enum + { + OPCODE = 0x12, + }; + uint8_t m_Opcode; // 0 + unsigned m_EVPD : 1; // 1 + unsigned m_Reserved_1 : 7; + uint8_t m_PageCode; // 2 + uint16_t m_AllocationLength; // 3 + uint8_t m_Control; // 5 +} ; // 6 + +//////////////////////////////////////////////////////////////////////////////// +class CScsiCmdInquiry_StandardData +//////////////////////////////////////////////////////////////////////////////// +{ +public: + unsigned m_PeripheralDeviceType : 5; // 0 + unsigned m_PeripheralQualifier : 3; + unsigned m_Reserved_1 : 6; // 1 + unsigned m_LUCong : 1; + unsigned m_RMB : 1; + uint8_t m_Version; // 2 + unsigned m_ResponseDataFormat : 4; // 3 + unsigned m_HiSup : 1; + unsigned m_NormACA : 1; + unsigned m_Reserved_2 : 1; + unsigned m_Reserved_3 : 1; + uint8_t m_AdditionalLength; // 4 + unsigned m_Protect : 1; // 5 + unsigned m_Reserved_4 : 2; + unsigned m_3PC : 1; + unsigned m_TPGS : 2; + unsigned m_ACC : 1; + unsigned m_SCCS : 1; + unsigned m_ADDR16 : 1; // 6 + unsigned m_Reserved_5 : 2; + unsigned m_Obsolete_1 : 1; + unsigned m_MultiP : 1; + unsigned m_VS1 : 1; + unsigned m_EncServ : 1; + unsigned m_Obsolete_2 : 1; + unsigned m_VS2 : 1; // 7 + unsigned m_CmdQue : 1; + unsigned m_Reserved_6 : 1; + unsigned m_Obsolete_3 : 1; + unsigned m_Sync : 1; + unsigned m_WBus16 : 1; + unsigned m_Reserved_7 : 1; + unsigned m_Obsolete_4 : 1; + uint8_t m_T10VendorId[8]; // 8 + uint8_t m_ProductId[16]; // 16 + uint8_t m_ProductRevisionLevel[4]; // 32 +}; // 36 + +//////////////////////////////////////////////////////////////////////////////// +class CScsiCmdSecurityProtocolIn +//////////////////////////////////////////////////////////////////////////////// +{ +public: + enum + { + OPCODE = 0XA2, + }; + uint8_t m_Opcode; // 0 + uint8_t m_SecurityProtocol; // 1 + uint16_t m_SecurityProtocolSpecific; // 2 + unsigned m_Reserved_1 : 7; // 4 + unsigned m_INC_512 : 1; + uint8_t m_Reserved_2; // 5 + uint32_t m_AllocationLength; // 6 + uint8_t m_Reserved_3[1]; // 10 + uint8_t m_Control; // 11 +}; // 12 + +//////////////////////////////////////////////////////////////////////////////// +class CScsiCmdSecurityProtocolOut +//////////////////////////////////////////////////////////////////////////////// +{ +public: + enum + { + OPCODE = 0XB5, + }; + uint8_t m_Opcode; // 0 + uint8_t m_SecurityProtocol; // 1 + uint16_t m_SecurityProtocolSpecific; // 2 + unsigned m_Reserved_1 : 7; // 4 + unsigned m_INC_512 : 1; + uint8_t m_Reserved_2; // 5 + uint32_t m_TransferLength; // 6 + uint8_t m_Reserved_3[1]; // 10 + uint8_t m_Control; // 11 +}; // 12 + +#pragma pack(pop) \ No newline at end of file diff --git a/sedutil-master/Common/LICENSE.txt b/sedutil-master/Common/LICENSE.txt new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/sedutil-master/Common/LICENSE.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/sedutil-master/Common/ReadMe.txt b/sedutil-master/Common/ReadMe.txt new file mode 100644 index 0000000..06ffc04 --- /dev/null +++ b/sedutil-master/Common/ReadMe.txt @@ -0,0 +1,39 @@ +This software is Copyright 2014-2017 Bright Plaza Inc. + +This file is part of sedutil. + +sedutil is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +sedutil is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with sedutil. If not, see . + +***** Warning ****** PROPER USE OF CERTAIN FEATURES OF THIS PROGRAM +***** Warning ****** **WILL** CAUSE AN UNRECOVERABLE LOSS ALL OF THE DATA ON YOUR +***** Warning ****** DRIVE +***** Warning ****** +***** Warning ****** A FAILURE OF AND/OR IMPROPER USE OF THIS PROGRAM +***** Warning ****** COULD CAUSE AN UNRECOVERABLE LOSS ALL OF THE DATA ON YOUR +***** Warning ****** DRIVE AND/OR PREVENT THE DRIVE FROM BEING USED AT +***** Warning ****** ALL EVER AGAIN +***** Warning ****** +***** Warning ****** IF YOU ARE UNSURE OF WHAT YOU ARE DOING THEN +***** Warning ****** *PLEASE* GET SOME HELP USING THIS PROGRAM. + ***** Warning ****** + +You must be administrator/root to run this program + +In Linux libata.allow_tpm must be set to 1. Either via adding libata.allow_tpm=1 to the kernel flags at boot time +or changing the contents of /sys/module/libata/parameters/allow_tpm to a from a "0" to a "1" on a running system. + +Currently the only operation that a general user would want to use is the PSID revert function +see linux/PSIDRevert_LINUX.txt or win32/PSIDRevert_WINDOWS.txt + +Source code is available on GitHub at https://github.com/Drive-Trust-Alliance/sedutil diff --git a/sedutil-master/Common/log.h b/sedutil-master/Common/log.h new file mode 100644 index 0000000..8c08c40 --- /dev/null +++ b/sedutil-master/Common/log.h @@ -0,0 +1,361 @@ +/* + * This software is Copyright 2007 Petru Marginean + * + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * For more information, please refer to + * + * + * simple logging class discussed in Dr Dobs journal + * http://www.drdobbs.com/cpp/logging-in-c/201804215 + * + * changed the naming a little, converted to safe printf's + * and added IFLOG() macro to support calling procedure only + * if we are at/above a specific log level + */ + +#ifndef __LOG_H__ +#define __LOG_H__ + +#include +#include +#include +#include +#include "DtaOptions.h" + +inline std::string NowTime(); + +enum TLogLevel { + E, W, I, D, D1, D2, D3, D4 +}; + +template +class Log { +public: + Log(); + virtual ~Log(); + std::ostringstream& Get(TLogLevel level = I); +public: + static TLogLevel& Level(); + static std::string ToString(TLogLevel level); + static TLogLevel FromString(const std::string& level); + static TLogLevel FromInt(const int level); +protected: + std::ostringstream os; +private: + Log(const Log&); + Log& operator =(const Log&); +}; + +template +Log::Log() { +} + +template +std::ostringstream& Log::Get(TLogLevel level) { + os << "- " << NowTime(); + os << " " << ToString(level) << ": "; + // os << std::string(level > D ? level - D : 0, '\t'); + return os; +} + +template +Log::~Log() { + os << std::endl; + T::Output(os.str()); +} + +template +TLogLevel& Log::Level() { + static TLogLevel Level = D4; + return Level; +} + +template +std::string Log::ToString(TLogLevel level) { + static const char* const buffer[] = {"ERR ", "WARN", "INFO", "DBG ", "DBG1", "DBG2", "DBG3", "DBG4"}; + return buffer[level]; +} + +template +TLogLevel Log::FromString(const std::string& level) { + if (level == "DEBUG4") + return D4; + if (level == "DEBUG3") + return D3; + if (level == "DEBUG2") + return D2; + if (level == "DEBUG1") + return D1; + if (level == "DEBUG") + return D; + if (level == "INFO") + return I; + if (level == "WARN") + return W; + if (level == "ERROR") + return E; + Log().Get(W) << "Unknown logging level '" << level << "'. Using INFO level as default."; + return I; +} + +template +TLogLevel Log::FromInt(const int level) { + if (level == 7) + return D4; + if (level == 6) + return D3; + if (level == 5) + return D2; + if (level == 4) + return D1; + if (level == 3) + return D; + if (level == 2) + return I; + if (level == 1) + return W; + if (level == 0) + return E; + Log().Get(W) << "Unknown logging level '" << level << "'. Using INFO level as default."; + return I; +} + +template +class RLog { +public: + RLog(); + virtual ~RLog(); + std::ostringstream& Get(TLogLevel level = I, sedutiloutput format = sedutilReadable); +public: + static TLogLevel& Level(); + static std::string ToString(TLogLevel level); + static TLogLevel FromString(const std::string& level); + static TLogLevel FromInt(const int level); +protected: + std::ostringstream os; +private: + RLog(const RLog&); + RLog& operator =(const RLog&); + TLogLevel curlevel; + sedutiloutput outputformat; +}; + +template +RLog::RLog() { +} + +template +std::ostringstream& RLog::Get(TLogLevel level, sedutiloutput output_format) { + curlevel = level; + outputformat = output_format; + if (output_format == sedutilNormal) { + os << "- " << NowTime(); + os << " " << ToString(level) << ": "; + } + // os << std::string(level > D ? level - D : 0, '\t'); + return os; +} + +template +RLog::~RLog() { + os << std::endl; + if ((curlevel == I) && (outputformat != sedutilNormal)) + T::Output(os.str()); + else + T::OutputErr(os.str()); +} + +template +TLogLevel& RLog::Level() { + static TLogLevel Level = D4; + return Level; +} + +template +std::string RLog::ToString(TLogLevel level) { + static const char* const buffer[] = {"ERR ", "WARN", "INFO", "DBG ", "DBG1", "DBG2", "DBG3", "DBG4"}; + return buffer[level]; +} + +template +TLogLevel RLog::FromString(const std::string& level) { + if (level == "DEBUG4") + return D4; + if (level == "DEBUG3") + return D3; + if (level == "DEBUG2") + return D2; + if (level == "DEBUG1") + return D1; + if (level == "DEBUG") + return D; + if (level == "INFO") + return I; + if (level == "WARN") + return W; + if (level == "ERROR") + return E; + RLog().Get(W, sedutilNormal) << "Unknown logging level '" << level << "'. Using INFO level as default."; + return I; +} + +template +TLogLevel RLog::FromInt(const int level) { + if (level == 7) + return D4; + if (level == 6) + return D3; + if (level == 5) + return D2; + if (level == 4) + return D1; + if (level == 3) + return D; + if (level == 2) + return I; + if (level == 1) + return W; + if (level == 0) + return E; + RLog().Get(W, sedutilNormal) << "Unknown logging level '" << level << "'. Using INFO level as default."; + return I; +} + + +class Output2FILE { +public: + static FILE*& Stream(); + static FILE*& StreamStdout(); + static void Output(const std::string& msg); + static void OutputErr(const std::string& msg); +}; + +inline FILE*& Output2FILE::StreamStdout() { + static FILE* pStream = stdout; + return pStream; +} + +inline FILE*& Output2FILE::Stream() { + static FILE* pStream = stderr; + return pStream; +} + +inline void Output2FILE::OutputErr(const std::string& msg) { + FILE* pStream = Stream(); + if (!pStream) + return; + fprintf(pStream, "%s", msg.c_str()); + fflush(pStream); +} + +inline void Output2FILE::Output(const std::string& msg) { + FILE* pStream = StreamStdout(); + if (!pStream) + return; + fprintf(pStream, "%s", msg.c_str()); + fflush(pStream); +} + +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) +#if defined (BUILDING_FILELOG_DLL) +#define FILELOG_DECLSPEC __declspec (dllexport) +#elif defined (USING_FILELOG_DLL) +#define FILELOG_DECLSPEC __declspec (dllimport) +#else +#define FILELOG_DECLSPEC +#endif // BUILDING_DBSIMPLE_DLL +#else +#define FILELOG_DECLSPEC +#endif // _WIN32 + +class FILELOG_DECLSPEC CLog : public Log { +}; +//typedef Log FILELog; + +class FILELOG_DECLSPEC RCLog : public RLog { +}; + +#ifndef CLOG_MAX_LEVEL +#define CLOG_MAX_LEVEL D4 +#endif + +#if 0 +#define LOG(level) \ + if (level > CLOG_MAX_LEVEL) ;\ + else if (level > CLog::Level() || !Output2FILE::Stream()) ; \ + else CLog().Get(level) +#endif + +#define IFLOG(level) \ + if (level > CLOG_MAX_LEVEL) ;\ + else if (level > CLog::Level() || !Output2FILE::Stream()) ; \ + else + +extern sedutiloutput outputFormat; + +#define LOGX(level) \ + if (level > CLOG_MAX_LEVEL) ;\ + else if (level > RCLog::Level() || !Output2FILE::Stream()) ; \ + else RCLog().Get(level, outputFormat) +#define LOG LOGX + +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) + +#include +#include + +inline std::string NowTime() { + const int MAX_LEN = 200; + char buffer[MAX_LEN]; + if (GetTimeFormatA(LOCALE_USER_DEFAULT, 0, 0, + "HH':'mm':'ss", buffer, MAX_LEN) == 0) + return "Error in NowTime()"; + + char result[100] = {0}; + static DWORD first = GetTickCount(); + sprintf_s(result, 99, "%s.%03ld", buffer, (long) (GetTickCount() - first) % 1000); + return result; +} + +#else + +#include + +inline std::string NowTime() { + char buffer[11]; + time_t t; + time(&t); + tm r = {0}; + strftime(buffer, sizeof (buffer), "%X", localtime_r(&t, &r)); + struct timeval tv; + gettimeofday(&tv, 0); + char result[100] = {0}; + snprintf(result, 95, "%s.%03ld", buffer, (long) tv.tv_usec / 1000); + return result; +} + +#endif //WIN32 + +#endif //__LOG_H__ diff --git a/sedutil-master/Common/pbkdf2/COPYING b/sedutil-master/Common/pbkdf2/COPYING new file mode 100644 index 0000000..0e259d4 --- /dev/null +++ b/sedutil-master/Common/pbkdf2/COPYING @@ -0,0 +1,121 @@ +Creative Commons Legal Code + +CC0 1.0 Universal + + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE + LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES + REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS + PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM + THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED + HEREUNDER. + +Statement of Purpose + +The laws of most jurisdictions throughout the world automatically confer +exclusive Copyright and Related Rights (defined below) upon the creator +and subsequent owner(s) (each and all, an "owner") of an original work of +authorship and/or a database (each, a "Work"). + +Certain owners wish to permanently relinquish those rights to a Work for +the purpose of contributing to a commons of creative, cultural and +scientific works ("Commons") that the public can reliably and without fear +of later claims of infringement build upon, modify, incorporate in other +works, reuse and redistribute as freely as possible in any form whatsoever +and for any purposes, including without limitation commercial purposes. +These owners may contribute to the Commons to promote the ideal of a free +culture and the further production of creative, cultural and scientific +works, or to gain reputation or greater distribution for their Work in +part through the use and efforts of others. + +For these and/or other purposes and motivations, and without any +expectation of additional consideration or compensation, the person +associating CC0 with a Work (the "Affirmer"), to the extent that he or she +is an owner of Copyright and Related Rights in the Work, voluntarily +elects to apply CC0 to the Work and publicly distribute the Work under its +terms, with knowledge of his or her Copyright and Related Rights in the +Work and the meaning and intended legal effect of CC0 on those rights. + +1. Copyright and Related Rights. A Work made available under CC0 may be +protected by copyright and related or neighboring rights ("Copyright and +Related Rights"). Copyright and Related Rights include, but are not +limited to, the following: + + i. the right to reproduce, adapt, distribute, perform, display, + communicate, and translate a Work; + ii. moral rights retained by the original author(s) and/or performer(s); +iii. publicity and privacy rights pertaining to a person's image or + likeness depicted in a Work; + iv. rights protecting against unfair competition in regards to a Work, + subject to the limitations in paragraph 4(a), below; + v. rights protecting the extraction, dissemination, use and reuse of data + in a Work; + vi. database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal + protection of databases, and under any national implementation + thereof, including any amended or successor version of such + directive); and +vii. other similar, equivalent or corresponding rights throughout the + world based on applicable law or treaty, and any national + implementations thereof. + +2. Waiver. To the greatest extent permitted by, but not in contravention +of, applicable law, Affirmer hereby overtly, fully, permanently, +irrevocably and unconditionally waives, abandons, and surrenders all of +Affirmer's Copyright and Related Rights and associated claims and causes +of action, whether now known or unknown (including existing as well as +future claims and causes of action), in the Work (i) in all territories +worldwide, (ii) for the maximum duration provided by applicable law or +treaty (including future time extensions), (iii) in any current or future +medium and for any number of copies, and (iv) for any purpose whatsoever, +including without limitation commercial, advertising or promotional +purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each +member of the public at large and to the detriment of Affirmer's heirs and +successors, fully intending that such Waiver shall not be subject to +revocation, rescission, cancellation, termination, or any other legal or +equitable action to disrupt the quiet enjoyment of the Work by the public +as contemplated by Affirmer's express Statement of Purpose. + +3. Public License Fallback. Should any part of the Waiver for any reason +be judged legally invalid or ineffective under applicable law, then the +Waiver shall be preserved to the maximum extent permitted taking into +account Affirmer's express Statement of Purpose. In addition, to the +extent the Waiver is so judged Affirmer hereby grants to each affected +person a royalty-free, non transferable, non sublicensable, non exclusive, +irrevocable and unconditional license to exercise Affirmer's Copyright and +Related Rights in the Work (i) in all territories worldwide, (ii) for the +maximum duration provided by applicable law or treaty (including future +time extensions), (iii) in any current or future medium and for any number +of copies, and (iv) for any purpose whatsoever, including without +limitation commercial, advertising or promotional purposes (the +"License"). The License shall be deemed effective as of the date CC0 was +applied by Affirmer to the Work. Should any part of the License for any +reason be judged legally invalid or ineffective under applicable law, such +partial invalidity or ineffectiveness shall not invalidate the remainder +of the License, and in such case Affirmer hereby affirms that he or she +will not (i) exercise any of his or her remaining Copyright and Related +Rights in the Work or (ii) assert any associated claims and causes of +action with respect to the Work, in either case contrary to Affirmer's +express Statement of Purpose. + +4. Limitations and Disclaimers. + + a. No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + b. Affirmer offers the Work as-is and makes no representations or + warranties of any kind concerning the Work, express, implied, + statutory or otherwise, including without limitation warranties of + title, merchantability, fitness for a particular purpose, non + infringement, or the absence of latent or other defects, accuracy, or + the present or absence of errors, whether or not discoverable, all to + the greatest extent permissible under applicable law. + c. Affirmer disclaims responsibility for clearing rights of other persons + that may apply to the Work or any use thereof, including without + limitation any person's Copyright and Related Rights in the Work. + Further, Affirmer disclaims responsibility for obtaining any necessary + consents, permissions or other rights required for any use of the + Work. + d. Affirmer understands and acknowledges that Creative Commons is not a + party to this document and has no duty or obligation with respect to + this CC0 or use of the Work. diff --git a/sedutil-master/Common/pbkdf2/bitops.h b/sedutil-master/Common/pbkdf2/bitops.h new file mode 100644 index 0000000..8afffc8 --- /dev/null +++ b/sedutil-master/Common/pbkdf2/bitops.h @@ -0,0 +1,273 @@ +/* + * cifra - embedded cryptography library + * Written in 2014 by Joseph Birr-Pixton + * + * To the extent possible under law, the author(s) have dedicated all + * copyright and related and neighboring rights to this software to the + * public domain worldwide. This software is distributed without any + * warranty. + * + * You should have received a copy of the CC0 Public Domain Dedication + * along with this software. If not, see + * . + */ + +#ifndef BITOPS_H +#define BITOPS_H + +#include +#include + +/* Assorted bitwise and common operations used in ciphers. */ + +/** Circularly rotate right x by n bits. + * 0 > n > 32. */ +static inline uint32_t rotr32(uint32_t x, unsigned n) +{ + return (x >> n) | (x << (32 - n)); +} + +/** Circularly rotate left x by n bits. + * 0 > n > 32. */ +static inline uint32_t rotl32(uint32_t x, unsigned n) +{ + return (x << n) | (x >> (32 - n)); +} + +/** Circularly rotate right x by n bits. + * 0 > n > 64. */ +static inline uint64_t rotr64(uint64_t x, unsigned n) +{ + return (x >> n) | (x << (64 - n)); +} + +/** Circularly rotate left x by n bits. + * 0 > n > 64. */ +static inline uint64_t rotl64(uint64_t x, unsigned n) +{ + return (x << n) | (x >> (64 - n)); +} + +/** Read 4 bytes from buf, as a 32-bit big endian quantity. */ +static inline uint32_t read32_be(const uint8_t buf[4]) +{ + return (buf[0] << 24) | + (buf[1] << 16) | + (buf[2] << 8) | + (buf[3]); +} + +/** Read 4 bytes from buf, as a 32-bit little endian quantity. */ +static inline uint32_t read32_le(const uint8_t buf[4]) +{ + return (buf[3] << 24) | + (buf[2] << 16) | + (buf[1] << 8) | + (buf[0]); +} + +/** Read 8 bytes from buf, as a 64-bit big endian quantity. */ +static inline uint64_t read64_be(const uint8_t buf[8]) +{ + uint32_t hi = read32_be(buf), + lo = read32_be(buf + 4); + return ((uint64_t)hi) << 32 | + lo; +} + +/** Read 8 bytes from buf, as a 64-bit little endian quantity. */ +static inline uint64_t read64_le(const uint8_t buf[8]) +{ + uint32_t hi = read32_le(buf + 4), + lo = read32_le(buf); + return ((uint64_t)hi) << 32 | + lo; +} + +/** Encode v as a 32-bit big endian quantity into buf. */ +static inline void write32_be(uint32_t v, uint8_t buf[4]) +{ + *buf++ = (v >> 24) & 0xff; + *buf++ = (v >> 16) & 0xff; + *buf++ = (v >> 8) & 0xff; + *buf = v & 0xff; +} + +/** Encode v as a 32-bit little endian quantity into buf. */ +static inline void write32_le(uint32_t v, uint8_t buf[4]) +{ + *buf++ = v & 0xff; + *buf++ = (v >> 8) & 0xff; + *buf++ = (v >> 16) & 0xff; + *buf = (v >> 24) & 0xff; +} + +/** Encode v as a 64-bit big endian quantity into buf. */ +static inline void write64_be(uint64_t v, uint8_t buf[8]) +{ + *buf++ = (v >> 56) & 0xff; + *buf++ = (v >> 48) & 0xff; + *buf++ = (v >> 40) & 0xff; + *buf++ = (v >> 32) & 0xff; + *buf++ = (v >> 24) & 0xff; + *buf++ = (v >> 16) & 0xff; + *buf++ = (v >> 8) & 0xff; + *buf = v & 0xff; +} + +/** Encode v as a 64-bit little endian quantity into buf. */ +static inline void write64_le(uint64_t v, uint8_t buf[8]) +{ + *buf++ = v & 0xff; + *buf++ = (v >> 8) & 0xff; + *buf++ = (v >> 16) & 0xff; + *buf++ = (v >> 24) & 0xff; + *buf++ = (v >> 32) & 0xff; + *buf++ = (v >> 40) & 0xff; + *buf++ = (v >> 48) & 0xff; + *buf = (v >> 56) & 0xff; +} + +/** out = in ^ b8. + * out and in may alias. */ +static inline void xor_b8(uint8_t *out, const uint8_t *in, uint8_t b8, size_t len) +{ + for (size_t i = 0; i < len; i++) + out[i] = in[i] ^ b8; +} + +/** out = x ^ y. + * out, x and y may alias. */ +static inline void xor_bb(uint8_t *out, const uint8_t *x, const uint8_t *y, size_t len) +{ + for (size_t i = 0; i < len; i++) + out[i] = x[i] ^ y[i]; +} + +/* out ^= x + * out and x may alias. */ +static inline void xor_words(uint32_t *out, const uint32_t *x, size_t nwords) +{ + for (size_t i = 0; i < nwords; i++) + out[i] ^= x[i]; +} + +/** Produce 0xffffffff if x == y, zero otherwise, without branching. */ +static inline uint32_t mask_u32(uint32_t x, uint32_t y) +{ + uint32_t diff = x ^ y; + uint32_t diff_is_zero = ~diff & (diff - 1); + return (diff_is_zero >> 31); +} + +/** Product 0xff if x == y, zero otherwise, without branching. */ +static inline uint8_t mask_u8(uint32_t x, uint32_t y) +{ + uint32_t diff = x ^ y; + uint8_t diff_is_zero = (uint8_t) (~diff & (diff - 1)); + return - (diff_is_zero >> 7); +} + +/** Select the ith entry from the given table of n values, in a side channel-silent + * way. */ +static inline uint32_t select_u32(uint32_t i, volatile const uint32_t *tab, uint32_t n) +{ + uint32_t r = 0; + + for (uint32_t ii = 0; ii < n; ii++) + { + uint32_t mask = mask_u32(i, ii); + r = (r & ~mask) | (tab[ii] & mask); + } + + return r; +} + +/** Select the ith entry from the given table of n values, in a side channel-silent + * way. */ +static inline uint8_t select_u8(uint32_t i, volatile const uint8_t *tab, uint32_t n) +{ + uint8_t r = 0; + + for (uint32_t ii = 0; ii < n; ii++) + { + uint8_t mask = mask_u8(i, ii); + r = (r & ~mask) | (tab[ii] & mask); + } + + return r; +} + +/** Select the ath, bth, cth and dth entries from the given table of n values, + * placing the results into a, b, c and d. */ +static inline void select_u8x4(uint8_t *a, uint8_t *b, uint8_t *c, uint8_t *d, + volatile const uint8_t *tab, uint32_t n) +{ + uint8_t ra = 0, + rb = 0, + rc = 0, + rd = 0; + uint8_t mask; + + for (uint32_t i = 0; i < n; i++) + { + uint8_t item = tab[i]; + + mask = mask_u8(*a, i); ra = (ra & ~mask) | (item & mask); + mask = mask_u8(*b, i); rb = (rb & ~mask) | (item & mask); + mask = mask_u8(*c, i); rc = (rc & ~mask) | (item & mask); + mask = mask_u8(*d, i); rd = (rd & ~mask) | (item & mask); + } + + *a = ra; + *b = rb; + *c = rc; + *d = rd; +} + +/** out ^= if0 or if1, depending on the value of bit. */ +static inline void select_xor128(uint32_t out[4], + const uint32_t if0[4], + const uint32_t if1[4], + uint8_t bit) +{ + uint32_t mask1 = mask_u32(bit, 1); + uint32_t mask0 = ~mask1; + + out[0] ^= (if0[0] & mask0) | (if1[0] & mask1); + out[1] ^= (if0[1] & mask0) | (if1[1] & mask1); + out[2] ^= (if0[2] & mask0) | (if1[2] & mask1); + out[3] ^= (if0[3] & mask0) | (if1[3] & mask1); +} + +/** Increments the integer stored at v (of non-zero length len) + * with the least significant byte first. */ +static inline void incr_le(uint8_t *v, size_t len) +{ + size_t i = 0; + while (1) + { + if (++v[i] != 0) + return; + i++; + if (i == len) + return; + } +} + +/** Increments the integer stored at v (of non-zero length len) + * with the most significant byte last. */ +static inline void incr_be(uint8_t *v, size_t len) +{ + len--; + while (1) + { + if (++v[len] != 0) + return; + if (len == 0) + return; + len--; + } +} + +#endif diff --git a/sedutil-master/Common/pbkdf2/blockwise.c b/sedutil-master/Common/pbkdf2/blockwise.c new file mode 100644 index 0000000..182c8c5 --- /dev/null +++ b/sedutil-master/Common/pbkdf2/blockwise.c @@ -0,0 +1,195 @@ +/* + * cifra - embedded cryptography library + * Written in 2014 by Joseph Birr-Pixton + * + * To the extent possible under law, the author(s) have dedicated all + * copyright and related and neighboring rights to this software to the + * public domain worldwide. This software is distributed without any + * warranty. + * + * You should have received a copy of the CC0 Public Domain Dedication + * along with this software. If not, see + * . + */ + +#include "blockwise.h" +#include "bitops.h" +#include "handy.h" +#include "tassert.h" + +#include + +void cf_blockwise_accumulate(uint8_t *partial, size_t *npartial, size_t nblock, + const void *inp, size_t nbytes, + cf_blockwise_in_fn process, + void *ctx) +{ + cf_blockwise_accumulate_final(partial, npartial, nblock, + inp, nbytes, + process, process, ctx); +} + +void cf_blockwise_accumulate_final(uint8_t *partial, size_t *npartial, size_t nblock, + const void *inp, size_t nbytes, + cf_blockwise_in_fn process, + cf_blockwise_in_fn process_final, + void *ctx) +{ + const uint8_t *bufin = inp; + assert(partial && *npartial < nblock); + assert(inp || !nbytes); + assert(process && ctx); + + /* If we have partial data, copy in to buffer. */ + if (*npartial && nbytes) + { + size_t space = nblock - *npartial; + size_t taken = MIN(space, nbytes); + + memcpy(partial + *npartial, bufin, taken); + + bufin += taken; + nbytes -= taken; + *npartial += taken; + + /* If that gives us a full block, process it. */ + if (*npartial == nblock) + { + if (nbytes == 0) + process_final(ctx, partial); + else + process(ctx, partial); + *npartial = 0; + } + } + + /* now nbytes < nblock or *npartial == 0. */ + + /* If we have a full block of data, process it directly. */ + while (nbytes >= nblock) + { + /* Partial buffer must be empty, or we're ignoring extant data */ + assert(*npartial == 0); + + if (nbytes == nblock) + process_final(ctx, bufin); + else + process(ctx, bufin); + bufin += nblock; + nbytes -= nblock; + } + + /* Finally, if we have remaining data, buffer it. */ + while (nbytes) + { + size_t space = nblock - *npartial; + size_t taken = MIN(space, nbytes); + + memcpy(partial + *npartial, bufin, taken); + + bufin += taken; + nbytes -= taken; + *npartial += taken; + + /* If we started with *npartial, we must have copied it + * in first. */ + assert(*npartial < nblock); + } +} + +void cf_blockwise_xor(uint8_t *partial, size_t *npartial, size_t nblock, + const void *inp, void *outp, size_t nbytes, + cf_blockwise_out_fn process, void *ctx) +{ + const uint8_t *inb = inp; + uint8_t *outb = outp; + + assert(partial && *npartial < nblock); + assert(inp || !nbytes); + assert(process && ctx); + + while (nbytes) + { + /* If we're out of material, and need more, produce a block. */ + if (*npartial == 0) + { + process(ctx, partial); + *npartial = nblock; + } + + size_t offset = nblock - *npartial; + size_t taken = MIN(*npartial, nbytes); + xor_bb(outb, inb, partial + offset, taken); + *npartial -= taken; + nbytes -= taken; + outb += taken; + inb += taken; + } +} + +void cf_blockwise_acc_byte(uint8_t *partial, size_t *npartial, + size_t nblock, + uint8_t byte, size_t nbytes, + cf_blockwise_in_fn process, + void *ctx) +{ + /* only memset the whole of the block once */ + int filled = 0; + + while (nbytes) + { + size_t start = *npartial; + size_t count = MIN(nbytes, nblock - start); + + if (!filled) + memset(partial + start, byte, count); + + if (start == 0 && count == nblock) + filled = 1; + + if (start + count == nblock) + { + process(ctx, partial); + *npartial = 0; + } else { + *npartial += count; + } + + nbytes -= count; + } +} + +void cf_blockwise_acc_pad(uint8_t *partial, size_t *npartial, + size_t nblock, + uint8_t fbyte, uint8_t mbyte, uint8_t lbyte, + size_t nbytes, + cf_blockwise_in_fn process, + void *ctx) +{ + + switch (nbytes) + { + case 0: break; + case 1: fbyte ^= lbyte; + cf_blockwise_accumulate(partial, npartial, nblock, &fbyte, 1, process, ctx); + break; + case 2: + cf_blockwise_accumulate(partial, npartial, nblock, &fbyte, 1, process, ctx); + cf_blockwise_accumulate(partial, npartial, nblock, &lbyte, 1, process, ctx); + break; + default: + cf_blockwise_accumulate(partial, npartial, nblock, &fbyte, 1, process, ctx); + + /* If the middle and last bytes differ, then process the last byte separately. + * Otherwise, just extend the middle block size. */ + if (lbyte != mbyte) + { + cf_blockwise_acc_byte(partial, npartial, nblock, mbyte, nbytes - 2, process, ctx); + cf_blockwise_accumulate(partial, npartial, nblock, &lbyte, 1, process, ctx); + } else { + cf_blockwise_acc_byte(partial, npartial, nblock, mbyte, nbytes - 1, process, ctx); + } + + break; + } +} diff --git a/sedutil-master/Common/pbkdf2/blockwise.h b/sedutil-master/Common/pbkdf2/blockwise.h new file mode 100644 index 0000000..a20ff95 --- /dev/null +++ b/sedutil-master/Common/pbkdf2/blockwise.h @@ -0,0 +1,147 @@ +/* + * cifra - embedded cryptography library + * Written in 2014 by Joseph Birr-Pixton + * + * To the extent possible under law, the author(s) have dedicated all + * copyright and related and neighboring rights to this software to the + * public domain worldwide. This software is distributed without any + * warranty. + * + * You should have received a copy of the CC0 Public Domain Dedication + * along with this software. If not, see + * . + */ + +#ifndef BLOCKWISE_H +#define BLOCKWISE_H + +#include +#include + +/* Processing function for cf_blockwise_accumulate. */ +typedef void (*cf_blockwise_in_fn)(void *ctx, const uint8_t *data); + +/* Processing function for cf_blockwise_xor. */ +typedef void (*cf_blockwise_out_fn)(void *ctx, uint8_t *data); + +/* This function manages the common abstraction of accumulating input in + * a buffer, and processing it when a full block is available. + * + * partial is the buffer (maintained by the caller) + * on entry, npartial is the currently valid count of used bytes on + * the front of partial. + * on exit, npartial is updated to reflect the status of partial. + * nblock is the blocksize to accumulate -- partial must be at least + * this long! + * input is the new data to process, of length nbytes. + * process is the processing function, passed ctx and a pointer + * to the data to process (always exactly nblock bytes long!) + * which may not neccessarily be the same as partial. + */ +void cf_blockwise_accumulate(uint8_t *partial, size_t *npartial, + size_t nblock, + const void *input, size_t nbytes, + cf_blockwise_in_fn process, + void *ctx); + +/* This function manages the common abstraction of accumulating input in + * a buffer, and processing it when a full block is available. + * This version supports calling a different processing function for + * the last block. + * + * partial is the buffer (maintained by the caller) + * on entry, npartial is the currently valid count of used bytes on + * the front of partial. + * on exit, npartial is updated to reflect the status of partial. + * nblock is the blocksize to accumulate -- partial must be at least + * this long! + * input is the new data to process, of length nbytes. + * process is the processing function, passed ctx and a pointer + * to the data to process (always exactly nblock bytes long!) + * which may not neccessarily be the same as partial. + * process_final is called last (but may not be called at all if + * all input is buffered). + */ +void cf_blockwise_accumulate_final(uint8_t *partial, size_t *npartial, + size_t nblock, + const void *input, size_t nbytes, + cf_blockwise_in_fn process, + cf_blockwise_in_fn process_final, + void *ctx); + +/* This function manages XORing an input stream with a keystream + * to produce an output stream. The keystream is produced in blocks + * (ala a block cipher in counter mode). + * + * partial is the keystream buffer (maintained by the caller) + * on entry, *npartial is the currently valid count of bytes in partial: + * unused bytes are at the *end*. So *npartial = 4 means the last four + * bytes of partial are usable as keystream. + * on exit, npartial is updated to reflect the new state of partial. + * nblock is the blocksize to accumulate -- partial must be at least + * this long! + * input is the new data to process, of length nbytes. + * output is where to write input xored with the keystream -- also length + * nbytes. + * process is the processing function, passed ctx and partial which it + * should fill with fresh key stream. + */ +void cf_blockwise_xor(uint8_t *partial, size_t *npartial, + size_t nblock, + const void *input, void *output, size_t nbytes, + cf_blockwise_out_fn newblock, + void *ctx); + +/* This function processes a single byte a number of times. It's useful + * for padding, and more efficient than calling cf_blockwise_accumulate + * a bunch of times. + * + * partial is the buffer (maintained by the caller) + * on entry, npartial is the currently valid count of used bytes on + * the front of partial. + * on exit, npartial is updated to reflect the status of partial. + * nblock is the blocksize to accumulate -- partial must be at least + * this long! + * process is the processing function, passed ctx and a pointer + * to the data to process (always exactly nblock bytes long!) + * which may not neccessarily be the same as partial. + * byte is the byte to process, nbytes times. + */ +void cf_blockwise_acc_byte(uint8_t *partial, size_t *npartial, + size_t nblock, + uint8_t byte, size_t nbytes, + cf_blockwise_in_fn process, + void *ctx); + +/* This function attempts to process patterns of bytes common in + * block cipher padding. + * + * This takes three bytes: + * - a first byte, fbyte, + * - a middle byte, mbyte, + * - a last byte, lbyte. + * + * If nbytes is zero, nothing happens. + * If nbytes is one, the byte fbyte ^ lbyte is processed. + * If nbytes is two, the fbyte then lbyte are processed. + * If nbytes is three or more, fbyte, then one or more mbytes, then fbyte + * is processed. + * + * partial is the buffer (maintained by the caller) + * on entry, npartial is the currently valid count of used bytes on + * the front of partial. + * on exit, npartial is updated to reflect the status of partial. + * nblock is the blocksize to accumulate -- partial must be at least + * this long! + * process is the processing function, passed ctx and a pointer + * to the data to process (always exactly nblock bytes long!) + * which may not neccessarily be the same as partial. + */ +void cf_blockwise_acc_pad(uint8_t *partial, size_t *npartial, + size_t nblock, + uint8_t fbyte, uint8_t mbyte, uint8_t lbyte, + size_t nbytes, + cf_blockwise_in_fn process, + void *ctx); + +#endif diff --git a/sedutil-master/Common/pbkdf2/chash.c b/sedutil-master/Common/pbkdf2/chash.c new file mode 100644 index 0000000..4ee5d76 --- /dev/null +++ b/sedutil-master/Common/pbkdf2/chash.c @@ -0,0 +1,28 @@ +/* + * cifra - embedded cryptography library + * Written in 2014 by Joseph Birr-Pixton + * + * To the extent possible under law, the author(s) have dedicated all + * copyright and related and neighboring rights to this software to the + * public domain worldwide. This software is distributed without any + * warranty. + * + * You should have received a copy of the CC0 Public Domain Dedication + * along with this software. If not, see + * . + */ + +#include "chash.h" +#include "handy.h" +#include "tassert.h" + +void cf_hash(const cf_chash *h, const void *m, size_t nm, uint8_t *out) +{ + cf_chash_ctx ctx; + assert(h); + h->init(&ctx); + h->update(&ctx, m, nm); + h->digest(&ctx, out); + mem_clean(&ctx, sizeof ctx); +} + diff --git a/sedutil-master/Common/pbkdf2/chash.h b/sedutil-master/Common/pbkdf2/chash.h new file mode 100644 index 0000000..8f2e201 --- /dev/null +++ b/sedutil-master/Common/pbkdf2/chash.h @@ -0,0 +1,137 @@ +/* + * cifra - embedded cryptography library + * Written in 2014 by Joseph Birr-Pixton + * + * To the extent possible under law, the author(s) have dedicated all + * copyright and related and neighboring rights to this software to the + * public domain worldwide. This software is distributed without any + * warranty. + * + * You should have received a copy of the CC0 Public Domain Dedication + * along with this software. If not, see + * . + */ + +#ifndef CHASH_H +#define CHASH_H + +#include +#include + +/** + * General hash function description + * ================================= + * This allows us to make use of hash functions without depending + * on a specific one. This is useful in implementing, for example, + * :doc:`HMAC `. + */ + +/* .. c:type:: cf_chash_init + * Hashing initialisation function type. + * + * Functions of this type should initialise the context in preparation + * for hashing a message with `cf_chash_update` functions. + * + * :rtype: void + * :param ctx: hash function-specific context structure. + */ +typedef void (*cf_chash_init)(void *ctx); + +/* .. c:type:: cf_chash_update + * Hashing data processing function type. + * + * Functions of this type hash `count` bytes of data at `data`, + * updating the contents of `ctx`. + * + * :rtype: void + * :param ctx: hash function-specific context structure. + * :param data: input data to hash. + * :param count: number of bytes to hash. + */ +typedef void (*cf_chash_update)(void *ctx, const void *data, size_t count); + +/* .. c:type:: cf_chash_digest + * Hashing completion function type. + * + * Functions of this type complete a hashing operation, + * writing :c:member:`cf_chash.hashsz` bytes to `hash`. + * + * This function does not change `ctx` -- any padding which needs doing + * must be done seperately (in a copy of `ctx`, say). + * + * This means you can interlave `_update` and `_digest` calls to + * learn `H(A)` and `H(A || B)` without hashing `A` twice. + * + * :rtype: void + * :param ctx: hash function-specific context structure. + * :param hash: location to write hash result. + */ +typedef void (*cf_chash_digest)(const void *ctx, uint8_t *hash); + +/* .. c:type:: cf_chash + * This type describes an incremental hash function in an abstract way. + * + * .. c:member:: cf_chash.hashsz + * The hash function's output, in bytes. + * + * .. c:member:: cf_chash.blocksz + * The hash function's internal block size, in bytes. + * + * .. c:member:: cf_chash.init + * Context initialisation function. + * + * .. c:member:: cf_chash:update + * Data processing function. + * + * .. c:member:: cf_chash:digest + * Completion function. + * + */ +typedef struct +{ + size_t hashsz; + size_t blocksz; + + cf_chash_init init; + cf_chash_update update; + cf_chash_digest digest; +} cf_chash; + +/* .. c:macro:: CF_CHASH_MAXCTX + * The maximum size of a :c:type:`cf_chash_ctx`. This allows + * use to put a structure in automatic storage that can + * store working data for any supported hash function. */ +#define CF_CHASH_MAXCTX 360 + +/* .. c:macro:: CF_CHASH_MAXBLK + * Maximum hash function block size (in bytes). */ +#define CF_CHASH_MAXBLK 128 + +/* .. c:macro:: CF_MAXHASH + * Maximum hash function output (in bytes). */ +#define CF_MAXHASH 64 + +/* .. c:type:: cf_chash_ctx + * A type usable with any `cf_chash` as a context. */ +typedef union +{ + uint8_t ctx[CF_CHASH_MAXCTX]; + uint16_t u16; + uint32_t u32; + uint64_t u64; +} cf_chash_ctx; + +/* .. c:function:: $DECL + * One shot hashing: `out = h(m)`. + * + * Using the hash function `h`, `nm` bytes at `m` are hashed and `h->hashsz` bytes + * of result is written to the buffer `out`. + * + * :param h: hash function description. + * :param m: message buffer. + * :param nm: message length. + * :param out: hash result buffer (written). + */ +void cf_hash(const cf_chash *h, const void *m, size_t nm, uint8_t *out); + +#endif diff --git a/sedutil-master/Common/pbkdf2/handy.h b/sedutil-master/Common/pbkdf2/handy.h new file mode 100644 index 0000000..166b77c --- /dev/null +++ b/sedutil-master/Common/pbkdf2/handy.h @@ -0,0 +1,74 @@ +#ifndef HANDY_H +#define HANDY_H + +#include +#include +#include + +/* + * Handy CPP defines and C inline functions. + */ + +/* Evaluates to the number of items in array-type variable arr. */ +#define ARRAYCOUNT(arr) (sizeof arr / sizeof arr[0]) + +/* Normal MIN/MAX macros. Evaluate argument expressions only once. */ +#define MIN(x, y) (x) < (y) ? (x) : (y) +#define MAX(x, y) (x) > (y) ? (x) : (y) + +/* Swap two values. Uses GCC type inference magic. */ +#define SWAP(x, y) \ + do { \ + typeof (x) __tmp = (x); \ + (x) = (y); \ + (y) = __tmp; \ + } while (0) + +/** Stringify its argument. */ +#define STRINGIFY(x) STRINGIFY_(x) +#define STRINGIFY_(x) #x + +/* Error handling macros. + * + * These expect a zero = success, non-zero = error convention. + */ + +/** Error: return. + * + * If the expression fails, return the error from this function. */ +#define ER(expr) do { typeof (expr) err_ = (expr); if (err_) return err_; } while (0) + +/** Error: goto. + * + * If the expression fails, goto x_err. Assumes defn of label + * x_err and 'error_type err'. */ +#define EG(expr) do { err = (expr); if (err) goto x_err; } while (0) + +/** Like memset(ptr, 0, len), but not allowed to be removed by + * compilers. */ +static inline void mem_clean(volatile void *v, size_t len) +{ + if (len) + { + memset((void *) v, 0, len); + (void) *((volatile uint8_t *) v); + } +} + +/** Returns 1 if len bytes at va equal len bytes at vb, 0 if they do not. + * Does not leak length of common prefix through timing. */ +static inline unsigned mem_eq(const void *va, const void *vb, size_t len) +{ + const volatile uint8_t *a = va; + const volatile uint8_t *b = vb; + uint8_t diff = 0; + + while (len--) + { + diff |= *a++ ^ *b++; + } + + return !diff; +} + +#endif diff --git a/sedutil-master/Common/pbkdf2/hmac.c b/sedutil-master/Common/pbkdf2/hmac.c new file mode 100644 index 0000000..98646d7 --- /dev/null +++ b/sedutil-master/Common/pbkdf2/hmac.c @@ -0,0 +1,106 @@ +/* + * cifra - embedded cryptography library + * Written in 2014 by Joseph Birr-Pixton + * + * To the extent possible under law, the author(s) have dedicated all + * copyright and related and neighboring rights to this software to the + * public domain worldwide. This software is distributed without any + * warranty. + * + * You should have received a copy of the CC0 Public Domain Dedication + * along with this software. If not, see + * . + */ + +#include "hmac.h" +#include "chash.h" +#include "bitops.h" +#include "handy.h" +#include "tassert.h" + +#include + +void cf_hmac_init(cf_hmac_ctx *ctx, + const cf_chash *hash, + const uint8_t *key, size_t nkey) +{ + assert(ctx); + assert(hash); + + mem_clean(ctx, sizeof *ctx); + ctx->hash = hash; + + /* Prepare key: */ + uint8_t k[CF_CHASH_MAXBLK]; + + /* Shorten long keys. */ + if (nkey > hash->blocksz) + { + /* Standard doesn't cover case where blocksz < hashsz. + * FIPS186-1 seems to want to append a negative number of zero bytes. + * In any case, we only have a k buffer of CF_CHASH_MAXBLK! */ + assert(hash->hashsz <= hash->blocksz); + + cf_hash(hash, key, nkey, k); + key = k; + nkey = hash->hashsz; + } + + /* Right zero-pad short keys. */ + if (k != key) + memcpy(k, key, nkey); + if (hash->blocksz > nkey) + memset(k + nkey, 0, hash->blocksz - nkey); + + /* Start inner hash computation */ + uint8_t blk[CF_CHASH_MAXBLK]; + + xor_b8(blk, k, 0x36, hash->blocksz); + hash->init(&ctx->inner); + hash->update(&ctx->inner, blk, hash->blocksz); + + /* And outer. */ + xor_b8(blk, k, 0x5c, hash->blocksz); + hash->init(&ctx->outer); + hash->update(&ctx->outer, blk, hash->blocksz); + + mem_clean(blk, sizeof blk); + mem_clean(k, sizeof k); +} + +void cf_hmac_update(cf_hmac_ctx *ctx, const void *data, size_t ndata) +{ + assert(ctx && ctx->hash); + + ctx->hash->update(&ctx->inner, data, ndata); +} + +void cf_hmac_finish(cf_hmac_ctx *ctx, uint8_t *out) +{ + assert(ctx && ctx->hash); + assert(out); + + uint8_t innerh[CF_MAXHASH]; + ctx->hash->digest(&ctx->inner, innerh); + + ctx->hash->update(&ctx->outer, innerh, ctx->hash->hashsz); + ctx->hash->digest(&ctx->outer, out); + + mem_clean(ctx, sizeof *ctx); +} + +void cf_hmac(const uint8_t *key, size_t nkey, + const uint8_t *msg, size_t nmsg, + uint8_t *out, + const cf_chash *hash) +{ + cf_hmac_ctx ctx; + + assert(out); + assert(hash); + + cf_hmac_init(&ctx, hash, key, nkey); + cf_hmac_update(&ctx, msg, nmsg); + cf_hmac_finish(&ctx, out); +} + diff --git a/sedutil-master/Common/pbkdf2/hmac.h b/sedutil-master/Common/pbkdf2/hmac.h new file mode 100644 index 0000000..2f9ea7b --- /dev/null +++ b/sedutil-master/Common/pbkdf2/hmac.h @@ -0,0 +1,78 @@ +/* + * cifra - embedded cryptography library + * Written in 2014 by Joseph Birr-Pixton + * + * To the extent possible under law, the author(s) have dedicated all + * copyright and related and neighboring rights to this software to the + * public domain worldwide. This software is distributed without any + * warranty. + * + * You should have received a copy of the CC0 Public Domain Dedication + * along with this software. If not, see + * . + */ + +#ifndef HMAC_H +#define HMAC_H + +#include +#include + +#include "chash.h" + +/** + * HMAC + * ==== + * This is a one-shot and incremental interface to computing + * HMAC with any hash function. + * + * (Note: HMAC with SHA3 is possible, but is probably not a + * sensible thing to want.) + */ + +/* .. c:type:: cf_hmac_ctx + * HMAC incremental interface context. + * + * .. c:member:: cf_hmac_ctx.hash + * Hash function description. + * + * .. c:member:: cf_hmac_ctx.inner + * Inner hash computation. + * + * .. c:member:: cf_hmac_ctx.outer + * Outer hash computation. + */ +typedef struct +{ + const cf_chash *hash; + cf_chash_ctx inner; + cf_chash_ctx outer; +} cf_hmac_ctx; + +/* .. c:function:: $DECL + * Set up ctx for computing a HMAC using the given hash and key. */ +void cf_hmac_init(cf_hmac_ctx *ctx, + const cf_chash *hash, + const uint8_t *key, size_t nkey); + +/* .. c:function:: $DECL + * Input data. */ +void cf_hmac_update(cf_hmac_ctx *ctx, + const void *data, size_t ndata); + +/* .. c:function:: $DECL + * Finish and compute HMAC. + * `ctx->hash->hashsz` bytes are written to `out`. */ +void cf_hmac_finish(cf_hmac_ctx *ctx, uint8_t *out); + +/* .. c:function:: $DECL + * One shot interface: compute `HMAC_hash(key, msg)`, writing the + * answer (which is `hash->hashsz` long) to `out`. + * + * This function does not fail. */ +void cf_hmac(const uint8_t *key, size_t nkey, + const uint8_t *msg, size_t nmsg, + uint8_t *out, + const cf_chash *hash); + +#endif diff --git a/sedutil-master/Common/pbkdf2/pbkdf2.c b/sedutil-master/Common/pbkdf2/pbkdf2.c new file mode 100644 index 0000000..fce6a22 --- /dev/null +++ b/sedutil-master/Common/pbkdf2/pbkdf2.c @@ -0,0 +1,84 @@ +/* + * cifra - embedded cryptography library + * Written in 2014 by Joseph Birr-Pixton + * + * To the extent possible under law, the author(s) have dedicated all + * copyright and related and neighboring rights to this software to the + * public domain worldwide. This software is distributed without any + * warranty. + * + * You should have received a copy of the CC0 Public Domain Dedication + * along with this software. If not, see + * . + */ + +#include "pbkdf2.h" +#include "hmac.h" +#include "bitops.h" +#include "handy.h" +#include "tassert.h" + +#include + +static void F(const cf_hmac_ctx *startctx, + uint32_t counter, + const uint8_t *salt, size_t nsalt, + uint32_t iterations, + uint8_t *out) +{ + uint8_t U[CF_MAXHASH]; + size_t hashsz = startctx->hash->hashsz; + + uint8_t countbuf[4]; + write32_be(counter, countbuf); + + /* First iteration: + * U_1 = PRF(P, S || INT_32_BE(i)) + */ + cf_hmac_ctx ctx = *startctx; + cf_hmac_update(&ctx, salt, nsalt); + cf_hmac_update(&ctx, countbuf, sizeof countbuf); + cf_hmac_finish(&ctx, U); + memcpy(out, U, hashsz); + + /* Subsequent iterations: + * U_c = PRF(P, U_{c-1}) + */ + for (uint32_t i = 1; i < iterations; i++) + { + ctx = *startctx; + cf_hmac_update(&ctx, U, hashsz); + cf_hmac_finish(&ctx, U); + xor_bb(out, out, U, hashsz); + } +} + +void cf_pbkdf2_hmac(const uint8_t *pw, size_t npw, + const uint8_t *salt, size_t nsalt, + uint32_t iterations, + uint8_t *out, size_t nout, + const cf_chash *hash) +{ + uint32_t counter = 1; + uint8_t block[CF_MAXHASH]; + + assert(iterations); + assert(out && nout); + assert(hash); + + /* Starting point for inner loop. */ + cf_hmac_ctx ctx; + cf_hmac_init(&ctx, hash, pw, npw); + + while (nout) + { + F(&ctx, counter, salt, nsalt, iterations, block); + + size_t taken = MIN(nout, hash->hashsz); + memcpy(out, block, taken); + out += taken; + nout -= taken; + counter++; + } +} + diff --git a/sedutil-master/Common/pbkdf2/pbkdf2.h b/sedutil-master/Common/pbkdf2/pbkdf2.h new file mode 100644 index 0000000..2f30484 --- /dev/null +++ b/sedutil-master/Common/pbkdf2/pbkdf2.h @@ -0,0 +1,47 @@ +/* + * cifra - embedded cryptography library + * Written in 2014 by Joseph Birr-Pixton + * + * To the extent possible under law, the author(s) have dedicated all + * copyright and related and neighboring rights to this software to the + * public domain worldwide. This software is distributed without any + * warranty. + * + * You should have received a copy of the CC0 Public Domain Dedication + * along with this software. If not, see + * . + */ + +#ifndef PBKDF2_H +#define PBKDF2_H + +#include +#include + +#include "chash.h" + +/** + * PBKDF2-HMAC + * =========== + * This is PBKDF2 as described by PKCS#5/RFC2898 with HMAC as the PRF. + */ + +/* .. c:function:: $DECL + * This computes PBKDF2-HMAC with the given hash functon. + * + * :param pw: password input buffer. + * :param npw: password length. + * :param salt: salt input buffer. + * :param nsalt: salt length. + * :param iterations: non-zero iteration count. Tune this for performance/security tradeoff. + * :param out: key material output buffer. `nout` bytes are written here. + * :param nout: key material length. + * :param hash: hash function description. + */ +void cf_pbkdf2_hmac(const uint8_t *pw, size_t npw, + const uint8_t *salt, size_t nsalt, + uint32_t iterations, + uint8_t *out, size_t nout, + const cf_chash *hash); + +#endif diff --git a/sedutil-master/Common/pbkdf2/sha1.c b/sedutil-master/Common/pbkdf2/sha1.c new file mode 100644 index 0000000..8b7d02f --- /dev/null +++ b/sedutil-master/Common/pbkdf2/sha1.c @@ -0,0 +1,150 @@ +/* + * cifra - embedded cryptography library + * Written in 2014 by Joseph Birr-Pixton + * + * To the extent possible under law, the author(s) have dedicated all + * copyright and related and neighboring rights to this software to the + * public domain worldwide. This software is distributed without any + * warranty. + * + * You should have received a copy of the CC0 Public Domain Dedication + * along with this software. If not, see + * . + */ + +#include + +#include "sha1.h" +#include "blockwise.h" +#include "bitops.h" +#include "handy.h" +#include "tassert.h" + +void cf_sha1_init(cf_sha1_context *ctx) +{ + memset(ctx, 0, sizeof *ctx); + ctx->H[0] = 0x67452301; + ctx->H[1] = 0xefcdab89; + ctx->H[2] = 0x98badcfe; + ctx->H[3] = 0x10325476; + ctx->H[4] = 0xc3d2e1f0; +} + +static void sha1_update_block(void *vctx, const uint8_t *inp) +{ + cf_sha1_context *ctx = vctx; + + /* This is a 16-word window into the whole W array. */ + uint32_t W[16]; + + uint32_t a = ctx->H[0], + b = ctx->H[1], + c = ctx->H[2], + d = ctx->H[3], + e = ctx->H[4], + Wt; + + for (size_t t = 0; t < 80; t++) + { + /* For W[0..16] we process the input into W. + * For W[16..79] we compute the next W value: + * + * W[t] = (W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16]) <<< 1 + * + * But all W indices are reduced mod 16 into our window. + */ + if (t < 16) + { + W[t] = Wt = read32_be(inp); + inp += 4; + } else { + Wt = W[(t - 3) % 16] ^ W[(t - 8) % 16] ^ W[(t - 14) % 16] ^ W[(t - 16) % 16]; + Wt = rotl32(Wt, 1); + W[t % 16] = Wt; + } + + uint32_t f, k; + + if (t <= 19) + { + f = (b & c) | (~b & d); + k = 0x5a827999; + } else if (t <= 39) { + f = b ^ c ^ d; + k = 0x6ed9eba1; + } else if (t <= 59) { + f = (b & c) | (b & d) | (c & d); + k = 0x8f1bbcdc; + } else { + f = b ^ c ^ d; + k = 0xca62c1d6; + } + + uint32_t temp = rotl32(a, 5) + f + e + k + Wt; + e = d; + d = c; + c = rotl32(b, 30); + b = a; + a = temp; + } + + ctx->H[0] += a; + ctx->H[1] += b; + ctx->H[2] += c; + ctx->H[3] += d; + ctx->H[4] += e; + + ctx->blocks++; +} + +void cf_sha1_update(cf_sha1_context *ctx, const void *data, size_t nbytes) +{ + cf_blockwise_accumulate(ctx->partial, &ctx->npartial, sizeof ctx->partial, + data, nbytes, + sha1_update_block, ctx); +} + +void cf_sha1_digest(const cf_sha1_context *ctx, uint8_t hash[CF_SHA1_HASHSZ]) +{ + cf_sha1_context ours = *ctx; + cf_sha1_digest_final(&ours, hash); +} + +void cf_sha1_digest_final(cf_sha1_context *ctx, uint8_t hash[CF_SHA1_HASHSZ]) +{ + uint64_t digested_bytes = ctx->blocks; + digested_bytes = digested_bytes * CF_SHA1_BLOCKSZ + ctx->npartial; + uint64_t digested_bits = digested_bytes * 8; + + size_t padbytes = CF_SHA1_BLOCKSZ - ((digested_bytes + 8) % CF_SHA1_BLOCKSZ); + + /* Hash 0x80 00 ... block first. */ + cf_blockwise_acc_pad(ctx->partial, &ctx->npartial, sizeof ctx->partial, + 0x80, 0x00, 0x00, padbytes, + sha1_update_block, ctx); + + /* Now hash length. */ + uint8_t buf[8]; + write64_be(digested_bits, buf); + cf_sha1_update(ctx, buf, 8); + + /* We ought to have got our padding calculation right! */ + assert(ctx->npartial == 0); + + write32_be(ctx->H[0], hash + 0); + write32_be(ctx->H[1], hash + 4); + write32_be(ctx->H[2], hash + 8); + write32_be(ctx->H[3], hash + 12); + write32_be(ctx->H[4], hash + 16); + + memset(ctx, 0, sizeof *ctx); +} + +const cf_chash cf_sha1 = { + .hashsz = CF_SHA1_HASHSZ, + .blocksz = CF_SHA1_BLOCKSZ, + .init = (cf_chash_init) cf_sha1_init, + .update = (cf_chash_update) cf_sha1_update, + .digest = (cf_chash_digest) cf_sha1_digest +}; + diff --git a/sedutil-master/Common/pbkdf2/sha1.h b/sedutil-master/Common/pbkdf2/sha1.h new file mode 100644 index 0000000..4ca0e91 --- /dev/null +++ b/sedutil-master/Common/pbkdf2/sha1.h @@ -0,0 +1,91 @@ +/* + * cifra - embedded cryptography library + * Written in 2014 by Joseph Birr-Pixton + * + * To the extent possible under law, the author(s) have dedicated all + * copyright and related and neighboring rights to this software to the + * public domain worldwide. This software is distributed without any + * warranty. + * + * You should have received a copy of the CC0 Public Domain Dedication + * along with this software. If not, see + * . + */ + +#ifndef SHA1_H +#define SHA1_H + +#include +#include + +#include "chash.h" + +/** + * SHA1 + * ==== + * + * You shouldn't use this for anything new. + */ + +/* .. c:macro:: CF_SHA1_HASHSZ + * The output size of SHA1: 20 bytes. */ +#define CF_SHA1_HASHSZ 20 + +/* .. c:macro:: CF_SHA1_BLOCKSZ + * The block size of SHA1: 64 bytes. */ +#define CF_SHA1_BLOCKSZ 64 + +/* .. c:type:: cf_sha1_context + * Incremental SHA1 hashing context. + * + * .. c:member:: cf_sha1_context.H + * Intermediate values. + * + * .. c:member:: cf_sha1_context.partial + * Unprocessed input. + * + * .. c:member:: cf_sha1_context.npartial + * Number of bytes of unprocessed input. + * + * .. c:member:: cf_sha1_context.blocks + * Number of full blocks processed. + */ +typedef struct +{ + uint32_t H[5]; /* State. */ + uint8_t partial[CF_SHA1_BLOCKSZ]; /* Partial block of input. */ + uint32_t blocks; /* Number of full blocks processed into H. */ + size_t npartial; /* Number of bytes in prefix of partial. */ +} cf_sha1_context; + +/* .. c:function:: $DECL + * Sets up `ctx` ready to hash a new message. + */ +extern void cf_sha1_init(cf_sha1_context *ctx); + +/* .. c:function:: $DECL + * Hashes `nbytes` at `data`. Copies the data if there isn't enough to make + * a full block. + */ +extern void cf_sha1_update(cf_sha1_context *ctx, const void *data, size_t nbytes); + +/* .. c:function:: $DECL + * Finishes the hash operation, writing `CF_SHA1_HASHSZ` bytes to `hash`. + * + * This leaves `ctx` unchanged. + */ +extern void cf_sha1_digest(const cf_sha1_context *ctx, uint8_t hash[CF_SHA1_HASHSZ]); + +/* .. c:function:: $DECL + * Finishes the hash operation, writing `CF_SHA1_HASHSZ` bytes to `hash`. + * + * This destroys `ctx`, but uses less stack than :c:func:`cf_sha1_digest`. + */ +extern void cf_sha1_digest_final(cf_sha1_context *ctx, uint8_t hash[CF_SHA1_HASHSZ]); + +/* .. c:var:: cf_sha1 + * Abstract interface to SHA1. See :c:type:`cf_chash` for more information. + */ +extern const cf_chash cf_sha1; + +#endif diff --git a/sedutil-master/Common/pbkdf2/tassert.h b/sedutil-master/Common/pbkdf2/tassert.h new file mode 100644 index 0000000..58ebb4c --- /dev/null +++ b/sedutil-master/Common/pbkdf2/tassert.h @@ -0,0 +1,32 @@ +/* + * cifra - embedded cryptography library + * Written in 2014 by Joseph Birr-Pixton + * + * To the extent possible under law, the author(s) have dedicated all + * copyright and related and neighboring rights to this software to the + * public domain worldwide. This software is distributed without any + * warranty. + * + * You should have received a copy of the CC0 Public Domain Dedication + * along with this software. If not, see + * . + */ + +#ifndef TASSERT_H +#define TASSERT_H + +/* Tiny assert + * ----------- + * + * This is an assert(3) definition which doesn't include any + * strings, but just branches to abort(3) on failure. + */ + +#ifndef FULL_FAT_ASSERT +# include +# define assert(expr) do { if (!(expr)) abort(); } while (0) +#else +# include +#endif + +#endif diff --git a/sedutil-master/Common/sedutil.cpp b/sedutil-master/Common/sedutil.cpp new file mode 100644 index 0000000..6858c80 --- /dev/null +++ b/sedutil-master/Common/sedutil.cpp @@ -0,0 +1,278 @@ +/* C:B************************************************************************** +This software is Copyright 2014-2017 Bright Plaza Inc. + +This file is part of sedutil. + +sedutil is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +sedutil is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with sedutil. If not, see . + +* C:E********************************************************************** */ +#include +#include "os.h" +#include "DtaHashPwd.h" +#include "DtaOptions.h" +#include "DtaLexicon.h" +#include "DtaDevGeneric.h" +#include "DtaDevOpal1.h" +#include "DtaDevOpal2.h" +#include "DtaDevEnterprise.h" + +using namespace std; + +/* Default to output that omits timestamps and goes to stdout */ +sedutiloutput outputFormat = sedutilReadable; + +int isValidSEDDisk(char *devname) +{ + DtaDev * d; + d = new DtaDevGeneric(devname); + if (d->isPresent()) { + printf("%s", devname); + if (d->isAnySSC()) + printf(" SED %s%s%s ", (d->isOpal1() ? "1" : "-"), + (d->isOpal2() ? "2" : "-"), (d->isEprise() ? "E" : "-")); + else + printf("%s", " NO --- "); + cout << d->getModelNum() << " " << d->getFirmwareRev(); + cout << std::endl; + } + delete d; + return 0; +} + +int main(int argc, char * argv[]) +{ + DTA_OPTIONS opts; + DtaDev *tempDev = NULL, *d = NULL; + if (DtaOptions(argc, argv, &opts)) { + return DTAERROR_COMMAND_ERROR; + } + + if ((opts.action != sedutiloption::scan) && + (opts.action != sedutiloption::validatePBKDF2) && + (opts.action != sedutiloption::isValidSED)) { + if (opts.device > (argc - 1)) opts.device = 0; + tempDev = new DtaDevGeneric(argv[opts.device]); + if (NULL == tempDev) { + LOG(E) << "Create device object failed"; + return DTAERROR_OBJECT_CREATE_FAILED; + } + if ((!tempDev->isPresent()) || (!tempDev->isAnySSC())) { + LOG(E) << "Invalid or unsupported disk " << argv[opts.device]; + delete tempDev; + return DTAERROR_COMMAND_ERROR; + } + if (tempDev->isOpal2()) + d = new DtaDevOpal2(argv[opts.device]); + else + if (tempDev->isOpal1()) + d = new DtaDevOpal1(argv[opts.device]); + else + if (tempDev->isEprise()) + d = new DtaDevEnterprise(argv[opts.device]); + else + { + LOG(E) << "Unknown OPAL SSC "; + return DTAERROR_INVALID_COMMAND; + } + delete tempDev; + if (NULL == d) { + LOG(E) << "Create device object failed"; + return DTAERROR_OBJECT_CREATE_FAILED; + } + // make sure DtaDev::no_hash_passwords is initialized + d->no_hash_passwords = opts.no_hash_passwords; + + d->output_format = opts.output_format; + } + + switch (opts.action) { + case sedutiloption::initialSetup: + LOG(D) << "Performing initial setup to use sedutil on drive " << argv[opts.device]; + return (d->initialSetup(argv[opts.password])); + case sedutiloption::setup_SUM: + LOG(D) << "Performing SUM setup on drive " << argv[opts.device]; + return (d->setup_SUM(opts.lockingrange, atoll(argv[opts.lrstart]), + atoll(argv[opts.lrlength]), argv[opts.password], argv[opts.newpassword])); + break; + case sedutiloption::setSIDPassword: + LOG(D) << "Performing setSIDPassword "; + return d->setSIDPassword(argv[opts.password], argv[opts.newpassword]); + break; + case sedutiloption::setAdmin1Pwd: + LOG(D) << "Performing setPAdmin1Pwd "; + return d->setPassword(argv[opts.password], (char *) "Admin1", + argv[opts.newpassword]); + break; + case sedutiloption::loadPBAimage: + LOG(D) << "Loading PBA image " << argv[opts.pbafile] << " to " << opts.device; + return d->loadPBA(argv[opts.password], argv[opts.pbafile]); + break; + case sedutiloption::setLockingRange: + LOG(D) << "Setting Locking Range " << (uint16_t) opts.lockingrange << " " << (uint16_t) opts.lockingstate; + return d->setLockingRange(opts.lockingrange, opts.lockingstate, argv[opts.password]); + break; + case sedutiloption::setLockingRange_SUM: + LOG(D) << "Setting Locking Range " << (uint16_t)opts.lockingrange << " " << (uint16_t)opts.lockingstate << " in Single User Mode"; + return d->setLockingRange_SUM(opts.lockingrange, opts.lockingstate, argv[opts.password]); + break; + case sedutiloption::enableLockingRange: + LOG(D) << "Enabling Locking Range " << (uint16_t) opts.lockingrange; + return (d->configureLockingRange(opts.lockingrange, + (DTA_READLOCKINGENABLED | DTA_WRITELOCKINGENABLED), argv[opts.password])); + break; + case sedutiloption::disableLockingRange: + LOG(D) << "Disabling Locking Range " << (uint16_t) opts.lockingrange; + return (d->configureLockingRange(opts.lockingrange, DTA_DISABLELOCKING, + argv[opts.password])); + break; + case sedutiloption::readonlyLockingRange: + LOG(D) << "Enabling Locking Range " << (uint16_t)opts.lockingrange; + return (d->configureLockingRange(opts.lockingrange, + DTA_WRITELOCKINGENABLED, argv[opts.password])); + break; + case sedutiloption::setupLockingRange: + LOG(D) << "Setup Locking Range " << (uint16_t)opts.lockingrange; + return (d->setupLockingRange(opts.lockingrange, atoll(argv[opts.lrstart]), + atoll(argv[opts.lrlength]), argv[opts.password])); + break; + case sedutiloption::setupLockingRange_SUM: + LOG(D) << "Setup Locking Range " << (uint16_t)opts.lockingrange << " in Single User Mode"; + return (d->setupLockingRange_SUM(opts.lockingrange, atoll(argv[opts.lrstart]), + atoll(argv[opts.lrlength]), argv[opts.password])); + break; + case sedutiloption::listLockingRanges: + LOG(D) << "List Locking Ranges "; + return (d->listLockingRanges(argv[opts.password], -1)); + break; + case sedutiloption::listLockingRange: + LOG(D) << "List Locking Range[" << opts.lockingrange << "]"; + return (d->listLockingRanges(argv[opts.password], opts.lockingrange)); + break; + case sedutiloption::rekeyLockingRange: + LOG(D) << "Rekey Locking Range[" << opts.lockingrange << "]"; + return (d->rekeyLockingRange(opts.lockingrange, argv[opts.password])); + break; + case sedutiloption::setBandsEnabled: + LOG(D) << "Set bands Enabled"; + return (d->setBandsEnabled(-1, argv[opts.password])); + break; + case sedutiloption::setBandEnabled: + LOG(D) << "Set band[" << opts.lockingrange << "] enabled"; + return (d->setBandsEnabled(opts.lockingrange, argv[opts.password])); + break; + case sedutiloption::setMBRDone: + LOG(D) << "Setting MBRDone " << (uint16_t)opts.mbrstate; + return (d->setMBRDone(opts.mbrstate, argv[opts.password])); + break; + case sedutiloption::setMBREnable: + LOG(D) << "Setting MBREnable " << (uint16_t)opts.mbrstate; + return (d->setMBREnable(opts.mbrstate, argv[opts.password])); + break; + case sedutiloption::enableuser: + LOG(D) << "Performing enable user for user " << argv[opts.userid]; + return d->enableUser(argv[opts.password], argv[opts.userid]); + break; + case sedutiloption::activateLockingSP: + LOG(D) << "Activating the LockingSP on" << argv[opts.device]; + return d->activateLockingSP(argv[opts.password]); + break; + case sedutiloption::activateLockingSP_SUM: + LOG(D) << "Activating the LockingSP on" << argv[opts.device]; + return d->activateLockingSP_SUM(opts.lockingrange, argv[opts.password]); + break; + case sedutiloption::eraseLockingRange_SUM: + LOG(D) << "Erasing LockingRange " << opts.lockingrange << " on" << argv[opts.device]; + return d->eraseLockingRange_SUM(opts.lockingrange, argv[opts.password]); + break; + case sedutiloption::query: + LOG(D) << "Performing diskquery() on " << argv[opts.device]; + d->puke(); + return 0; + break; + case sedutiloption::scan: + LOG(D) << "Performing diskScan() "; + return(DtaDevOS::diskScan()); + break; + case sedutiloption::isValidSED: + LOG(D) << "Verify whether " << argv[opts.device] << "is valid SED or not"; + return isValidSEDDisk(argv[opts.device]); + break; + case sedutiloption::takeOwnership: + LOG(D) << "Taking Ownership of the drive at" << argv[opts.device]; + return d->takeOwnership(argv[opts.password]); + break; + case sedutiloption::revertLockingSP: + LOG(D) << "Performing revertLockingSP on " << argv[opts.device]; + return d->revertLockingSP(argv[opts.password], 0); + break; + case sedutiloption::setPassword: + LOG(D) << "Performing setPassword for user " << argv[opts.userid]; + return d->setPassword(argv[opts.password], argv[opts.userid], + argv[opts.newpassword]); + break; + case sedutiloption::setPassword_SUM: + LOG(D) << "Performing setPassword in SUM mode for user " << argv[opts.userid]; + return d->setNewPassword_SUM(argv[opts.password], argv[opts.userid], + argv[opts.newpassword]); + break; + case sedutiloption::revertTPer: + LOG(D) << "Performing revertTPer on " << argv[opts.device]; + return d->revertTPer(argv[opts.password], 0, 0); + break; + case sedutiloption::revertNoErase: + LOG(D) << "Performing revertLockingSP keep global locking range on " << argv[opts.device]; + return d->revertLockingSP(argv[opts.password], 1); + break; + case sedutiloption::validatePBKDF2: + LOG(D) << "Performing PBKDF2 validation "; + TestPBKDF2(); + break; + case sedutiloption::yesIreallywanttoERASEALLmydatausingthePSID: + case sedutiloption::PSIDrevert: + LOG(D) << "Performing a PSID Revert on " << argv[opts.device] << " with password " << argv[opts.password]; + return d->revertTPer(argv[opts.password], 1, 0); + break; + case sedutiloption::PSIDrevertAdminSP: + LOG(D) << "Performing a PSID RevertAdminSP on " << argv[opts.device] << " with password " << argv[opts.password]; + return d->revertTPer(argv[opts.password], 1, 1); + break; + case sedutiloption::eraseLockingRange: + LOG(D) << "Erase Locking Range " << (uint16_t)opts.lockingrange; + return (d->eraseLockingRange(opts.lockingrange, argv[opts.password])); + break; + case sedutiloption::objDump: + LOG(D) << "Performing objDump " ; + return d->objDump(argv[argc - 5], argv[argc - 4], argv[argc - 3], argv[argc - 2]); + break; + case sedutiloption::printDefaultPassword: + LOG(D) << "print default password"; + return d->printDefaultPassword(); + break; + case sedutiloption::rawCmd: + LOG(D) << "Performing cmdDump "; + return d->rawCmd(argv[argc - 7], argv[argc - 6], argv[argc - 5], argv[argc - 4], argv[argc - 3], argv[argc - 2]); + break; + case sedutiloption::readDataStore: + LOG(D) << "testing datastore"; + return d->readDataStore(argv[opts.filename], argv[opts.password]); + break; + case sedutiloption::writeDataStore: + LOG(D) << "writing file to datastore"; + return d->writeDataStore(argv[opts.filename], argv[opts.password]); + default: + LOG(E) << "Unable to determine what you want to do "; + usage(); + } + return DTAERROR_INVALID_COMMAND; +} diff --git a/sedutil-master/DTA_Contributor_Agreement_v2.docx b/sedutil-master/DTA_Contributor_Agreement_v2.docx new file mode 100644 index 0000000..162dbea Binary files /dev/null and b/sedutil-master/DTA_Contributor_Agreement_v2.docx differ diff --git a/sedutil-master/Doxyfile b/sedutil-master/Doxyfile new file mode 100644 index 0000000..9483d4d --- /dev/null +++ b/sedutil-master/Doxyfile @@ -0,0 +1,2303 @@ +# Doxyfile 1.8.6 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all text +# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv +# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv +# for the list of possible encodings. +# The default value is: UTF-8. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = "sedutil - Drive Trust Alliance SED Utility" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = + +# With the PROJECT_LOGO tag one can specify an logo or icon that is included in +# the documentation. The maximum height of the logo should not exceed 55 pixels +# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo +# to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where doxygen was started. If +# left blank the current directory will be used. + +OUTPUT_DIRECTORY = Doxygen + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub- +# directories (in 2 levels) under the output directory of each output format and +# will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. +# The default value is: NO. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, +# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), +# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, +# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, +# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, +# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, +# Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +# The default value is: YES. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# doxygen will generate a detailed section even if there is only a brief +# description. +# The default value is: NO. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. +# The default value is: NO. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = YES + +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = YES + +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a +# new page for each member. If set to NO, the documentation of a member will be +# part of the file/class/namespace that contains it. +# The default value is: NO. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:\n" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". You can put \n's in the value part of an alias to insert +# newlines. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding "class=itcl::class" +# will allow you to use the command class in the itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, Javascript, +# C#, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL. For instance to make +# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C +# (default is Fortran), use: inc=Fortran f=C. +# +# Note For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by by putting a % sign in front of the word +# or globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO only methods in the interface are +# included. +# The default value is: NO. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO these classes will be included in the various overviews. This option has +# no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# (class|struct|union) declarations. If set to NO these declarations will be +# included in the documentation. +# The default value is: NO. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file +# names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. +# The default value is: system dependent. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = YES + +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO the members will appear in declaration order. +# The default value is: YES. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the +# todo list. This list is created by putting \todo commands in the +# documentation. +# The default value is: YES. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the +# test list. This list is created by putting \test commands in the +# documentation. +# The default value is: YES. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if ... \endif and \cond +# ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES the list +# will mention the files that were used to generate the documentation. +# The default value is: YES. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. Do not use file names with spaces, bibtex cannot handle them. See +# also \cite for info how to create references. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = YES + +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some parameters +# in a documented function, or documenting parameters that don't exist or using +# markup commands wrongly. +# The default value is: YES. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO doxygen will only warn about wrong or incomplete parameter +# documentation, but not about the absence of documentation. +# The default value is: NO. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# The default value is: $file:$line: $text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. +# Note: If this tag is empty the current directory is searched. + +INPUT = ./ ./common ./linux + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: http://www.gnu.org/software/libiconv) for the list of +# possible encodings. +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank the +# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii, +# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, +# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, +# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, +# *.qsf, *.as and *.js. + +FILE_PATTERNS = + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = common/log.h + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# +# +# where is the value of the INPUT_FILTER tag, and is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER ) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = README.md + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# function all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES, then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = YES + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see http://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the config file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = YES + +# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in +# which the alphabetical index list will be split. +# Minimum value: 1, maximum value: 20, default value: 5. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all classes will +# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag +# can be used to specify a prefix (or a list of prefixes) that should be ignored +# while generating the index headers. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output +# The default value is: YES. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user- +# defined cascading style sheet that is included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefor more robust against future updates. +# Doxygen will copy the style sheet file to the output directory. For an example +# see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the stylesheet and background images according to +# this color. Hue is specified as an angle on a colorwheel, see +# http://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use grayscales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to NO can help when comparing the output of multiple runs. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: http://developer.apple.com/tools/xcode/), introduced with +# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a +# Makefile in the HTML output directory. Running make will produce the docset in +# that directory and running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on +# Windows. +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be +# written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = + +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler ( hhc.exe). If non-empty +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# The GENERATE_CHI flag controls if a separate .chi index file is generated ( +# YES) or that it should be included in the master .chm file ( NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# The BINARY_TOC flag controls whether a binary table of contents is generated ( +# YES) or a normal table of contents ( NO) in the .chm file. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- +# folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location of Qt's +# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the +# generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can +# further fine-tune the look of the index. As an example, the default style +# sheet generated by doxygen has an example that shows how to put an image at +# the root of the tree instead of the PROJECT_NAME. Since the tree basically has +# the same information as the tab index, you could consider setting +# DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 250 + +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are not +# supported properly for IE 6.0, but are supported on all modern browsers. +# +# Note that when changing this option you need to delete any form_*.png files in +# the HTML output directory before the changes have effect. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# http://www.mathjax.org) which uses client side Javascript for the rendering +# instead of using prerendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = NO + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. See the MathJax site (see: +# http://docs.mathjax.org/en/latest/output.html) for more details. +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility), NativeMML (i.e. MathML) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from http://www.mathjax.org before deployment. +# The default value is: http://cdn.mathjax.org/mathjax/latest. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use + S +# (what the is depends on the OS and browser, but it is typically +# , /