TSKPinFailureReport.m 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. /*
  2. TSKPinFailureReport.m
  3. TrustKit
  4. Copyright 2015 The TrustKit Project Authors
  5. Licensed under the MIT license, see associated LICENSE file for terms.
  6. See AUTHORS file for the list of project authors.
  7. */
  8. #import "TSKPinFailureReport.h"
  9. @implementation TSKPinFailureReport
  10. - (nonnull instancetype) initWithAppBundleId:(nonnull NSString *)appBundleId
  11. appVersion:(nonnull NSString *)appVersion
  12. appPlatform:(nonnull NSString *)appPlatform
  13. appPlatformVersion:(nonnull NSString *)appPlatformVersion
  14. appVendorId:(nonnull NSString *)appVendorId
  15. trustkitVersion:(nonnull NSString *)trustkitVersion
  16. hostname:(nonnull NSString *)serverHostname
  17. port:(nonnull NSNumber *)serverPort
  18. dateTime:(nonnull NSDate *)dateTime
  19. notedHostname:(nonnull NSString *)notedHostname
  20. includeSubdomains:(BOOL)includeSubdomains
  21. enforcePinning:(BOOL)enforcePinning
  22. validatedCertificateChain:(nonnull NSArray<NSString *> *)validatedCertificateChain
  23. knownPins:(nonnull NSArray<NSString *> *)knownPins
  24. validationResult:(TSKTrustEvaluationResult)validationResult
  25. expirationDate:(nullable NSDate *)knownPinsExpirationDate
  26. {
  27. self = [super init];
  28. if (self)
  29. {
  30. _appBundleId = appBundleId;
  31. _appVersion = appVersion;
  32. _appPlatform = appPlatform;
  33. _appVendorId = appVendorId;
  34. _trustkitVersion = trustkitVersion;
  35. _appPlatformVersion = appPlatformVersion;
  36. _hostname = serverHostname;
  37. _port = serverPort;
  38. _dateTime = dateTime;
  39. _notedHostname = notedHostname;
  40. _includeSubdomains = includeSubdomains;
  41. _enforcePinning = enforcePinning;
  42. _validatedCertificateChain = validatedCertificateChain;
  43. _knownPins = knownPins;
  44. _validationResult = validationResult;
  45. _knownPinsExpirationDate = knownPinsExpirationDate;
  46. }
  47. return self;
  48. }
  49. - (nonnull NSData *)json;
  50. {
  51. // NSDateFormatter (and NSNumberFormatter) is extremely expensive to initialize, doesn't
  52. // change, and is listed as explicitely thread safe, so lets reuse the instance.
  53. static NSDateFormatter *DateTimeFormatter = nil;
  54. static NSDateFormatter *DateFormatter = nil;
  55. static dispatch_once_t onceToken;
  56. dispatch_once(&onceToken, ^{
  57. /// Date AND time formatter for JSON
  58. DateTimeFormatter = ({
  59. NSDateFormatter *df = [[NSDateFormatter alloc] init];
  60. // Explicitely set the locale to avoid an iOS 8 bug
  61. // http://stackoverflow.com/questions/29374181/nsdateformatter-hh-returning-am-pm-on-ios-8-device
  62. df.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
  63. df.dateFormat = @"yyyy-MM-dd'T'HH:mm:ss'Z'";
  64. df.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];
  65. df;
  66. });
  67. /// Date ONLY formatter
  68. DateFormatter = ({
  69. NSDateFormatter *df = [[NSDateFormatter alloc] init];
  70. // Explicitely set the locale to avoid an iOS 8 bug
  71. // http://stackoverflow.com/questions/29374181/nsdateformatter-hh-returning-am-pm-on-ios-8-device
  72. df.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
  73. df.dateFormat = @"yyyy-MM-dd";
  74. df.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];
  75. df;
  76. });
  77. });
  78. id dateStr = [NSNull null];
  79. if (self.dateTime)
  80. {
  81. dateStr = [DateTimeFormatter stringFromDate:self.dateTime] ?: [NSNull null];
  82. }
  83. id expirationDateStr = [NSNull null];
  84. if (self.knownPinsExpirationDate)
  85. {
  86. // For the expiration date, only return the expiration day, as specified in the pinning policy
  87. expirationDateStr = [DateFormatter stringFromDate:self.knownPinsExpirationDate] ?: [NSNull null];
  88. }
  89. // Create the dictionary
  90. NSDictionary *requestData = @{
  91. @"app-bundle-id": self.appBundleId,
  92. @"app-version": self.appVersion,
  93. @"app-platform": self.appPlatform,
  94. @"app-platform-version": self.appPlatformVersion,
  95. @"app-vendor-id": self.appVendorId,
  96. @"trustkit-version": self.trustkitVersion,
  97. @"date-time": dateStr,
  98. @"hostname": self.hostname,
  99. @"port": self.port,
  100. @"noted-hostname": self.notedHostname,
  101. @"include-subdomains": @(self.includeSubdomains),
  102. @"enforce-pinning": @(self.enforcePinning),
  103. @"validated-certificate-chain": self.validatedCertificateChain,
  104. @"known-pins": self.knownPins,
  105. @"validation-result": @(self.validationResult),
  106. @"known-pins-expiration-date": expirationDateStr
  107. };
  108. NSError *error;
  109. NSData *jsonData = [NSJSONSerialization dataWithJSONObject:requestData options:(NSJSONWritingOptions)0 error:&error];
  110. // FIXME: error is unhandled.
  111. return jsonData;
  112. }
  113. - (nonnull NSMutableURLRequest *)requestToUri:(NSURL *)reportUri
  114. {
  115. NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:reportUri];
  116. request.HTTPMethod = @"POST";
  117. [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
  118. request.HTTPBody = [self json];
  119. return request;
  120. }
  121. @end