1<?php
2/*
3 *
4 * Copyright 2008-2010 GuardTime AS
5 *
6 * This file is part of the GuardTime PHP SDK.
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 *     http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 *
20 */
21
22/**
23 * @package http
24 */
25
26/**
27 * A collection of static methods for basic operations with timestamps.
28 *
29 * @package http
30 */
31class GTHttpClient {
32
33    /**
34     * Creates timestamp for the given dataHash using stamperUrl.
35     *
36     * @static
37     * @throws GTException thrown if timestamp creation fails
38     * @param  GTDataHash $dataHash data hash to create the timestamp for
39     * @param  string $stamperUrl stamping service url
40     * @return GTTimestamp a newly created short-term (signed) timestamp
41     */
42    public static function create(GTDataHash $dataHash, $stamperUrl) {
43
44        $algorithm = new X509AlgorithmIdentifier();
45        $algorithm->setAlgorithm($dataHash->getHashAlgorithm()->getOid());
46
47        $message = new TSPMessageImprint();
48        $message->setHashedMessage($dataHash->getHashedMessage());
49        $message->setHashAlgorithm($algorithm);
50
51        $request = new TSPTimeStampReq();
52        $request->setMessageImprint($message);
53
54        $bytes = $request->encodeDER();
55        $bytes = GTUtil::fromByteArray($bytes);
56
57        $curl = curl_init();
58
59        curl_setopt($curl, CURLOPT_URL, $stamperUrl);
60        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
61        curl_setopt($curl, CURLOPT_BINARYTRANSFER, 1);
62        curl_setopt($curl, CURLOPT_POST, 1);
63        curl_setopt($curl, CURLOPT_POSTFIELDS, $bytes);
64
65        $bytes = curl_exec($curl);
66
67        if ($bytes === false) {
68            throw new GTException("Error creating timestamp, CURL error: " . curl_error($curl));
69        }
70
71        $bytes = GTUtil::toByteArray($bytes);
72
73        $response = new TSPTimeStampResp();
74        $response->decode(ASN1DER::decode($bytes));
75
76        return new GTTimestamp($response->getToken());
77    }
78
79    /**
80     * Extends the timestamp using the given extension service URL.
81     *
82     * @static
83     * @throws GTException if timestamp extension fails
84     * @param  GTTimestamp $timestamp timestamp to be extended
85     * @param  string $verifierUrl extension service URL
86     * @return void
87     */
88    public static function extend(GTTimestamp $timestamp, $verifierUrl) {
89
90        $request = new GTCertTokenRequest();
91        $request->setHistoryIdentifier(new GTBigInteger($timestamp->getProperty(GTTimestamp::HISTORY_ID)));
92
93        $bytes = $request->encodeDER();
94        $bytes = GTUtil::fromByteArray($bytes);
95
96        $curl = curl_init();
97
98        curl_setopt($curl, CURLOPT_URL, $verifierUrl);
99        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
100        curl_setopt($curl, CURLOPT_BINARYTRANSFER, 1);
101        curl_setopt($curl, CURLOPT_POST, 1);
102        curl_setopt($curl, CURLOPT_POSTFIELDS, $bytes);
103
104        $bytes = curl_exec($curl);
105
106        if ($bytes === false) {
107            throw new GTException("Error extending timestamp, CURL error: " . curl_error($curl));
108        }
109
110        $bytes = GTUtil::toByteArray($bytes);
111
112        $response = new GTCertTokenResponse();
113        $response->decode(ASN1DER::decode($bytes));
114
115        $timestamp->extend($response);
116
117    }
118
119    /**
120     * Verifies the given timestamp against the given dataHash.
121     *
122     * If a timestamp is not yet extended, automatic extension is attempted.
123     * If the automatic extension is successfull the extended timestamp is verified
124     * against the given publicationsFile.
125     *
126     * If the timestamp is already extended then the timestamp is verified against
127     * the given publications file.
128     *
129     * If the timestamp is not extended and extension is not possible the timestamp
130     * will be verified against short term signing certificates.
131     *
132     * @static
133     * @throws GTException
134     * @param  GTTimestamp $timestamp the timestamp to verify
135     * @param  GTDataHash $dataHash data hash to verify the timestamp against
136     * @param  null|string $verifierUrl extension url if automatic extension is to be attempted, null otherwise
137     * @param  GTPublicationsFile $publicationsFile publications file to verify the timestamp against
138     *
139     * @return GTVerificationResultHttp tmestamp verification result
140     */
141    public static function verify(GTTimestamp $timestamp, GTDataHash $dataHash, $verifierUrl, GTPublicationsFile $publicationsFile) {
142
143        if (empty($timestamp)) {
144            throw new GTException("Parameter timestamp is required");
145        }
146
147        if (empty($dataHash)) {
148            throw new GTException("Parameter dataHash is required");
149        }
150
151        if ($publicationsFile == null) {
152            throw new GTException("Invalid publications file: null");
153        }
154
155        $result = new GTVerificationResultHttp();
156
157        if ($verifierUrl === null) {
158            $extendable = false;
159
160        } else {
161            $extendable = $timestamp->isExtendable($publicationsFile);
162
163        }
164
165        if ($extendable) {
166
167            $result->updateStatus(GTVerificationResultHttp::EXTENSION_ATTEMPTED);
168
169            $request = new GTCertTokenRequest();
170            $request->setHistoryIdentifier(new GTBigInteger($timestamp->getProperty(GTTimestamp::HISTORY_ID)));
171
172            $bytes = $request->encodeDER();
173            $bytes = GTUtil::fromByteArray($bytes);
174
175            $curl = curl_init();
176
177            curl_setopt($curl, CURLOPT_URL, $verifierUrl);
178            curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
179            curl_setopt($curl, CURLOPT_BINARYTRANSFER, 1);
180            curl_setopt($curl, CURLOPT_POST, 1);
181            curl_setopt($curl, CURLOPT_POSTFIELDS, $bytes);
182
183            $bytes = curl_exec($curl);
184
185            if ($bytes === false) {
186                $result->updateStatus(GTVerificationResultHttp::SERVICE_UNREACHABLE_FAILURE);
187            }
188
189            $bytes = GTUtil::toByteArray($bytes);
190
191            $response = null;
192
193            try {
194                $response = new GTCertTokenResponse();
195                $response->decode(ASN1DER::decode($bytes));
196
197            } catch (GTException $e) {
198                $result->updateStatus(GTVerificationResultHttp::RESPONSE_FORMAT_FAILURE);
199                return $result;
200            }
201
202            $statusCode = ($response === null) ? -1 : $response->getStatusCode();
203
204            if ($statusCode == 0) {
205                $result->updateStatus(GTVerificationResultHttp::TIMESTAMP_GRANTED);
206
207            } else if ($statusCode == 1) {
208                $result->updateStatus(GTVerificationResultHttp::TIMESTAMP_GRANTED_WITH_MODS);
209
210            } else if ($statusCode == 2) {
211                $result->updateStatus(GTVerificationResultHttp::TIMESTAMP_REJECTED);
212
213            } else if ($statusCode == 3) {
214                $result->updateStatus(GTVerificationResultHttp::TIMESTAMP_WAITING);
215
216            } else if ($statusCode == 4) {
217                $result->updateStatus(GTVerificationResultHttp::REVOCATION_WARNING);
218
219            } else if ($statusCode == 5) {
220                $result->updateStatus(GTVerificationResultHttp::REVOCATION_NOTIFICATION);
221
222            }
223
224            if ($statusCode == 0 || $statusCode == 1) {
225
226                try {
227                    $timestamp->extend($response);
228
229                    $result->updateStatus(GTVerificationResultHttp::TIMESTAMP_EXTENDED);
230
231                } catch (GTException $e) {
232
233                    $gtResult = new GTVerificationResult();
234                    $gtResult->updateErrors(GTVerificationResult::SYNTACTIC_CHECK_FAILURE);
235
236                    $result->setGtResult($gtResult);
237
238                    return $result;
239                }
240
241                $gtResult = $timestamp->verify($dataHash, $publicationsFile);
242
243                $result->setGtResult($gtResult);
244
245            } else if ($statusCode > 1) {
246
247                $failCode = ($response == null) ? -1 : $response->getFailCode();
248
249                if ($failCode == -1) {
250                    $result->updateErrors(GTVerificationResultHttp::SERVICE_UNREACHABLE_FAILURE);
251
252                } else if ($failCode == 0) {
253                    $result->updateErrors(GTVerificationResultHttp::INVALID_ALGORITHM_FAILURE);
254
255                } else if ($failCode == 2) {
256                    $result->updateErrors(GTVerificationResultHttp::INVALID_REQUEST_FAILURE);
257
258                } else if ($failCode == 5) {
259                    $result->updateErrors(GTVerificationResultHttp::INVALID_DATA_FORMAT_FAILURE);
260
261                } else if ($failCode == 14) {
262                    $result->updateErrors(GTVerificationResultHttp::TIME_NOT_AVAILBLE_FAILURE);
263
264                } else if ($failCode == 15) {
265                    $result->updateErrors(GTVerificationResultHttp::UNACCEPTED_POLICY_FAILURE);
266
267                } else if ($failCode == 16) {
268                    $result->updateErrors(GTVerificationResultHttp::UNACCEPTED_EXTENSION_FAILURE);
269
270                } else if ($failCode == 17) {
271                    $result->updateErrors(GTVerificationResultHttp::ADDITIONAL_INFO_NOT_AVAILABLE_FAILURE);
272
273                } else if ($failCode == 25) {
274                    $result->updateErrors(GTVerificationResultHttp::SYSTEM_FAILURE);
275
276                } else if ($failCode == 100) {
277                    $result->updateErrors(GTVerificationResultHttp::TIMESTAMP_TOO_NEW_FAILURE);
278
279                } else if ($failCode == 101) {
280                    $result->updateErrors(GTVerificationResultHttp::TIMESTAMP_TOO_OLD_FAILURE);
281
282                }
283
284                if ($failCode != 100 && $failCode != 101) {
285                    return $result;
286                }
287
288            }
289        }
290
291        $gtResult = $timestamp->verify($dataHash, $publicationsFile);
292
293        $result->setGtResult($gtResult);
294
295        return $result;
296    }
297
298
299    /**
300     * Downloads publications file from the given url.
301     *
302     * Only basic syntax checking on the downloaded publications file is performaed.
303     * It is strongly recommended to verify the downloaded publications file.
304     *
305     * @static
306     * @throws GTException
307     * @param  string $url publications file URL
308     * @return GTPublicationsFile publications file
309     */
310    public static function getPublicationsFile($url) {
311
312        $curl = curl_init();
313
314        curl_setopt($curl, CURLOPT_URL, $url);
315        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
316        curl_setopt($curl, CURLOPT_BINARYTRANSFER, 1);
317
318        $bytes = curl_exec($curl);
319
320        if ($bytes === false) {
321            throw new GTException("Error downloading publications file, CURL error: " . curl_error($curl));
322        }
323
324        return new GTPublicationsFile(GTUtil::toByteArray($bytes));
325    }
326
327}
328
329?>
330