5 // Created by Michael Brouwer on 7/10/12.
6 // Copyright (c) 2012 Apple Inc. All rights reserved.
9 #include "utilities/der_plist.h"
10 #include "utilities/der_plist_internal.h"
11 #include "utilities/der_date.h"
13 #include "utilities/SecCFRelease.h"
14 #include "utilities/array_size.h"
16 #include <CoreFoundation/CoreFoundation.h>
17 #include <corecrypto/ccder.h>
19 #include "utilities_regressions.h"
21 #define kMaxResultSize 100
28 static struct test_case test_cases
[] =
30 { .value
= 0.0, .expected
= "20010101000000Z", },
31 { .value
= 1.0, .expected
= "20010101000001Z", },
32 { .value
= 0.1, .expected
= "20010101000000.1Z", },
33 { .value
= 0.0001, .expected
= "20010101000000.0001Z", },
34 { .value
= 128.0, .expected
= "20010101000208Z", },
35 { .value
= -1.0, .expected
= "20001231235959Z", },
36 { .value
= -0.9, .expected
= "20001231235959.1Z", },
37 { .value
= -129.0, .expected
= "20001231235751Z", },
38 { .value
= 1000.0, .expected
= "20010101001640Z", },
39 { .value
= 65280.0, .expected
= "20010101180800Z", },
40 { .value
= 41234576.0, .expected
= "20020423060256Z", },
41 { .value
= -412343576.0, .expected
= "19871208120704Z", },
42 { .value
= 381778873.238063, .expected
= "20130205174113.238063Z", },
43 { .value
= 381778873.638063, .expected
= "20130205174113.638063Z", },
44 { .value
= 1400603.141, .expected
= "20010117050323.141Z", },
45 { .value
= -412343576.238063, .expected
= "19871208120703.761937Z", },
46 { .value
= -412343576.638063, .expected
= "19871208120703.361937Z", },
47 { .value
= 5.000539014, .expected
= "20010101000005.000539014Z", },
48 { .value
= -5.00053901, .expected
= "20001231235954.99946099Z", },
49 { .value
= 0.000539014, .expected
= "20010101000000.000539014Z", },
50 { .value
= -0.00053901, .expected
= "20001231235959.99946099Z", },
51 { .value
= 11031400603.141, .expected
= "23500729055643.141Z", }, // Michael's 400th birthday
52 // Pedantic tests within 1 second of the epoch.
53 { .value
= 0.000100120234, .expected
= "20010101000000.000100120234Z", },
54 { .value
= 0.00000000000000000000000000000000000000000010012654182354326,
55 .expected
= "20010101000000.00000000000000000000000000000000000000000010012654182354326Z", },
56 { .value
= -0.00000000000000000000000000000000000000000010012654182354326,
57 .expected
= "20001231235959.99999999999999999999999999999999999999999989987345817645674Z", },
58 { .value
= 0.0001234522366234637, .expected
= "20010101000000.0001234522366234637Z", },
61 static CFStringRef
string_create_with_hex(const uint8_t* start
, const uint8_t* end
) {
62 CFMutableStringRef s
= CFStringCreateMutable(NULL
, 0);
63 CFStringAppendFormat(s
, 0, CFSTR(".size = %" PRIdPTR
", .res = { "), (intptr_t)(end
- start
));
65 CFStringAppendFormat(s
, 0, CFSTR("0x%02X, "), *start
++);
66 CFStringAppend(s
, CFSTR("},\n"));
70 static bool ok_der_date_is(int testnumber
, const char *expected
, const uint8_t *der
, const uint8_t *der_end
) {
71 size_t elen
= strlen(expected
);
73 const uint8_t *body
= ccder_decode_tl(CCDER_GENERALIZED_TIME
, &dlen
, der
, der_end
);
75 return fail("[%d] encoded date %@ expected %s not a generalized time", testnumber
, string_create_with_hex(der
, der_end
), expected
);
76 } else if (body
+ dlen
!= der_end
) {
77 return fail("[%d] Trailing garbage in encoded string after generalized time got: %@ expected: %s", testnumber
, string_create_with_hex(der
, der_end
), expected
);
78 } else if (dlen
!= elen
) {
79 return fail("[%d] encoded date len %zu != %zu got: %.*s expected: %s", testnumber
, dlen
, elen
, (int)dlen
, (char *)body
, expected
);
80 } else if (memcmp(body
, expected
, elen
)) {
81 return fail("[%d] encoded got: %.*s expected: %s", testnumber
, (int)dlen
, (char *)body
, expected
);
83 return pass("[%d] properly encoded %s", testnumber
, expected
);
87 static bool ok_date_equals(int testnumber
, CFDateRef decoded
, CFDateRef expected
) {
88 CFAbsoluteTime t1
= CFDateGetAbsoluteTime(decoded
);
89 CFAbsoluteTime t2
= CFDateGetAbsoluteTime(expected
);
90 if (-1.0 < t1
&& t1
< 1.0) {
91 // Dates near the epoch can't be off by more than 1 nanosecond. Other dates should be exactly right.
92 return ok((decoded
!= NULL
) && fabs(t1
- t2
) < 7e-18, "[%d] Delta too big %g %a != %a (%g != %g).", testnumber
, fabs(t1
- t2
), t1
, t2
, t1
, t2
);
94 return ok((decoded
!= NULL
) && CFEqual(decoded
, expected
), "[%d] Didn't make equal value %a != %a (%g != %g).", testnumber
, t1
, t2
, t1
, t2
);
98 #define kTestsPerTestCase 12
99 static void one_test(const struct test_case
* thisCase
, int testnumber
)
101 uint8_t buffer
[kMaxResultSize
];
102 uint8_t* buffer_end
= buffer
+ sizeof(buffer
);
104 CFDateRef initialValue
= CFDateCreate(NULL
, thisCase
->value
);
105 CFErrorRef error
= NULL
;
107 uint8_t* encoded
= der_encode_plist(initialValue
, &error
, buffer
, buffer_end
);
110 skip("der_encode_plist failed", 1,
111 ok(encoded
!= NULL
, "[%d] der_encode_plist failed: %@", testnumber
, error
));
112 ok_der_date_is(testnumber
, thisCase
->expected
, encoded
, buffer_end
);
114 CFReleaseNull(error
);
116 encoded
= der_encode_date(initialValue
, &error
, buffer
, buffer_end
);
119 skip("der_encode_date failed", 1,
120 ok(encoded
!= NULL
, "[%d] der_encode_date failed: %@", testnumber
, error
));
121 ok_der_date_is(testnumber
, thisCase
->expected
, encoded
, buffer_end
);
123 CFReleaseNull(error
);
125 CFDateRef decoded
= NULL
;
126 const uint8_t* decode_end
= der_decode_date(NULL
, kCFPropertyListMutableContainers
,
127 &decoded
, &error
, encoded
, buffer_end
);
128 ok(error
== NULL
, "[%d] der_decode_date failed: %@", testnumber
, error
);
129 CFReleaseNull(error
);
131 ok(decode_end
== buffer_end
, "[%d] didn't decode whole buffer", testnumber
);
132 ok_date_equals(testnumber
, decoded
, initialValue
);
134 CFPropertyListRef decoded_type
= NULL
;
136 decode_end
= der_decode_plist(NULL
, kCFPropertyListMutableContainers
,
137 &decoded_type
, &error
, encoded
, buffer_end
);
138 ok(error
== NULL
, "[%d] der_decode_plist failed: %@", testnumber
, error
);
139 CFReleaseNull(error
);
141 ok(decode_end
== buffer_end
, "[%d] didn't decode whole buffer", testnumber
);
142 ok_date_equals(testnumber
, decoded
, initialValue
);
144 is(der_sizeof_date(initialValue
, NULL
), ccder_sizeof(CCDER_GENERALIZED_TIME
, strlen(thisCase
->expected
)), "[%d] der_sizeof_date mismatch", testnumber
);
145 is(der_sizeof_plist(initialValue
, NULL
), ccder_sizeof(CCDER_GENERALIZED_TIME
, strlen(thisCase
->expected
)), "[%d] der_sizeof_plist mismatch", testnumber
);
147 CFReleaseSafe(initialValue
);
148 CFReleaseNull(decoded
);
149 CFReleaseNull(decoded_type
);
152 #define kTestCount (array_size(test_cases) * kTestsPerTestCase)
153 static void tests(void)
155 for (int testnumber
= 0; testnumber
< array_size(test_cases
); ++testnumber
)
156 one_test(test_cases
+ testnumber
, testnumber
);
159 int su_16_cfdate_der(int argc
, char *const *argv
)
161 plan_tests(kTestCount
);