Merge remote branch 'origin/pootle-import'
[enigma2.git] / lib / base / etpm.cpp
1 #include <sys/socket.h>
2 #include <fcntl.h>
3 #include <stdbool.h>
4 #include <stdlib.h>
5 #include <stdio.h>
6 #include <string.h>
7 #include <sys/un.h>
8 #include <unistd.h>
9 #include <openssl/bn.h>
10 #include <openssl/sha.h>
11 #include <lib/base/eerror.h>
12
13 #include "etpm.h"
14
15 eTPM::eTPM()
16 {
17         struct sockaddr_un addr;
18         unsigned char buf[8];
19         unsigned int tag;
20         size_t len;
21         unsigned char *val;
22
23         level2_cert_read = level3_cert_read = false;
24
25         addr.sun_family = AF_UNIX;
26         strcpy(addr.sun_path, TPMD_SOCKET);
27
28         fd = socket(PF_UNIX, SOCK_STREAM, 0);
29         if (fd < 0)
30         {
31                 eDebug("[eTPM] socket error");
32                 return;
33         }
34
35         if (connect(fd, (const struct sockaddr *)&addr, SUN_LEN(&addr)) < 0)
36         {
37                 eDebug("[eTPM] connect error");
38                 return;
39         }
40
41         buf[0] = TPMD_DT_LEVEL2_CERT;
42         buf[1] = TPMD_DT_LEVEL3_CERT;
43         if (!send_cmd(TPMD_CMD_GET_DATA, buf, 2))
44         {
45                 return;
46         }
47
48         val = (unsigned char*)recv_cmd(&tag, &len);
49         if (val == NULL)
50         {
51                 return;
52         }
53
54         parse_data(val, len);
55         free(val);
56 }
57
58 eTPM::~eTPM()
59 {
60
61 }
62
63 bool eTPM::send_cmd(enum tpmd_cmd cmd, const void *data, size_t len)
64 {
65         unsigned char buf[len + 4];
66
67         buf[0] = (cmd >> 8) & 0xff;
68         buf[1] = (cmd >> 0) & 0xff;
69         buf[2] = (len >> 8) & 0xff;
70         buf[3] = (len >> 0) & 0xff;
71         memcpy(&buf[4], data, len);
72
73         if (write(fd, buf, sizeof(buf)) != (ssize_t)sizeof(buf))
74         {
75                 fprintf(stderr, "%s: incomplete write\n", __func__);
76                 return false;
77         }
78
79         return true;
80 }
81
82 void* eTPM::recv_cmd(unsigned int *tag, size_t *len)
83 {
84         unsigned char buf[4];
85         void *val;
86
87         if (read(fd, buf, 4) != 4)
88         {
89                 fprintf(stderr, "%s: incomplete read\n", __func__);
90                 return NULL;
91         }
92
93         *tag = (buf[0] << 8) | buf[1];
94         *len = (buf[2] << 8) | buf[3];
95
96         val = malloc(*len);
97         if (val == NULL)
98                 return NULL;
99
100         ssize_t rd = read(fd, val, *len);
101         if (rd < 0)
102         {
103                 perror("eTPM::recv_cmd read");
104                 free(val);
105         }
106         else if ((size_t)rd != *len) {
107                 fprintf(stderr, "%s: incomplete read\n", __func__);
108                 free(val);
109                 return NULL;
110         }
111
112         return val;
113 }
114
115 void eTPM::parse_data(const unsigned char *data, size_t datalen)
116 {
117         unsigned int i;
118         unsigned int tag;
119         unsigned int len;
120         const unsigned char *val;
121
122         for (i = 0; i < datalen; i += len) {
123                 tag = data[i++];
124                 len = data[i++];
125                 val = &data[i];
126
127                 switch (tag) {
128                 case TPMD_DT_LEVEL2_CERT:
129                         if (len != 210)
130                                 break;
131                         memcpy(level2_cert, val, 210);
132                         level2_cert_read = true;
133                         break;
134                 case TPMD_DT_LEVEL3_CERT:
135                         if (len != 210)
136                                 break;
137                         memcpy(level3_cert, val, 210);
138                         level3_cert_read = true;
139                         break;
140                 }
141         }
142 }
143
144 std::string eTPM::getCert(cert_type type)
145 {
146         if (type == TPMD_DT_LEVEL2_CERT && level2_cert_read)
147                 return std::string((char*)level2_cert, 210);
148         else if (type == TPMD_DT_LEVEL3_CERT && level3_cert_read)
149                 return std::string((char*)level3_cert, 210);
150         return "";
151 }
152
153 std::string eTPM::challenge(std::string rnd)
154 {
155         if (rnd.length() == 8)
156         {
157                 if (!send_cmd(TPMD_CMD_COMPUTE_SIGNATURE, rnd.c_str(), 8))
158                         return "";
159
160                 unsigned int tag;
161                 size_t len;
162                 unsigned char *val = (unsigned char*)recv_cmd(&tag, &len);
163
164                 if (tag != TPMD_CMD_COMPUTE_SIGNATURE)
165                         return "";
166
167                 std::string ret((char*)val, len);
168                 free(val);
169                 return ret;
170         }
171         return "";
172 }