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