File: code_signature_mac.cc

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (148 lines) | stat: -rw-r--r-- 6,629 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/apps/app_shim/code_signature_mac.h"

#include "base/apple/bundle_locations.h"
#include "base/apple/foundation_util.h"
#include "base/apple/osstatus_logging.h"
#include "base/apple/scoped_cftyperef.h"
#include "base/debug/dump_without_crashing.h"
#include "base/strings/stringprintf.h"
#include "base/strings/sys_string_conversions.h"
#include "components/crash/core/common/crash_key.h"

namespace {
// A crash key that is used when dumping because of errors when validating code
// signatures.
crash_reporter::CrashKeyString<256> code_signature_crash_key("CodeSignature");

// This function logs the status and error_details using OSSTATUS_LOG(). It also
// calls base::debug::DumpWithoutCrashing() using code_signature_crash_key
// as a crash key. The status and error_details are appended to the crash key.
void DumpOSStatusError(OSStatus status, std::string error_details) {
  OSSTATUS_LOG(ERROR, status) << error_details;
  crash_reporter::ScopedCrashKeyString crash_key_value(
      &code_signature_crash_key,
      base::StringPrintf("%s: %s (%d)", error_details.c_str(),
                         logging::DescriptionFromOSStatus(status).c_str(),
                         status));
  base::debug::DumpWithoutCrashing();
}

// This function is similar to DumpOSStatusError(), however it operates without
// an OSStatus.
void DumpError(std::string error_details) {
  LOG(ERROR) << error_details;
  crash_reporter::ScopedCrashKeyString crash_key_value(
      &code_signature_crash_key, error_details);
  base::debug::DumpWithoutCrashing();
}
}  // namespace

namespace apps {

base::expected<base::apple::ScopedCFTypeRef<CFStringRef>,
               MissingRequirementReason>
FrameworkBundleDesignatedRequirementString() {
  // Note: Don't validate |framework_code|: We don't need to waste time
  // validating. We are only interested in discovering if the framework bundle
  // is code-signed, and if so what the designated requirement is.
  base::apple::ScopedCFTypeRef<CFURLRef> framework_url =
      base::apple::FilePathToCFURL(base::apple::FrameworkBundlePath());
  base::apple::ScopedCFTypeRef<SecStaticCodeRef> framework_code;
  OSStatus status = SecStaticCodeCreateWithPath(
      framework_url.get(), kSecCSDefaultFlags, framework_code.InitializeInto());

  // If the framework bundle is unsigned there is nothing else to do. We treat
  // this as success because there’s no identity to protect or even match, so
  // it’s not dangerous to let the shim connect.
  if (status == errSecCSUnsigned) {
    return base::unexpected(MissingRequirementReason::NoOrAdHocSignature);
  }

  // If there was an error obtaining the SecStaticCodeRef something is very
  // broken or something bad is happening, deny.
  if (status != errSecSuccess) {
    DumpOSStatusError(status, "SecStaticCodeCreateWithPath");
    return base::unexpected(MissingRequirementReason::Error);
  }

  // Copy the signing info from the SecStaticCodeRef.
  base::apple::ScopedCFTypeRef<CFDictionaryRef> framework_signing_info;
  status = SecCodeCopySigningInformation(
      framework_code.get(), kSecCSSigningInformation,
      framework_signing_info.InitializeInto());
  if (status != errSecSuccess) {
    DumpOSStatusError(status, "SecCodeCopySigningInformation");
    return base::unexpected(MissingRequirementReason::Error);
  }

  // Look up the code signing flags. If the flags are absent treat this as
  // unsigned. This decision is consistent with the StaticCode source:
  // https://github.com/apple-oss-distributions/Security/blob/Security-60157.40.30.0.1/OSX/libsecurity_codesigning/lib/StaticCode.cpp#L2270
  CFNumberRef framework_signing_info_flags =
      base::apple::GetValueFromDictionary<CFNumberRef>(
          framework_signing_info.get(), kSecCodeInfoFlags);
  if (!framework_signing_info_flags) {
    return base::unexpected(MissingRequirementReason::NoOrAdHocSignature);
  }

  // If the framework bundle is ad-hoc signed there is nothing else to
  // do. While the framework bundle is code-signed an ad-hoc signature does not
  // contain any identities to match against. Treat this as a success.
  //
  // Note: Using a long long to extract the value from the CFNumberRef to be
  // consistent with how it was packed by Security.framework.
  // https://github.com/apple-oss-distributions/Security/blob/Security-60157.40.30.0.1/OSX/libsecurity_utilities/lib/cfutilities.h#L262
  long long flags;
  if (!CFNumberGetValue(framework_signing_info_flags, kCFNumberLongLongType,
                        &flags)) {
    DumpError("CFNumberGetValue");
    return base::unexpected(MissingRequirementReason::Error);
  }
  if (static_cast<uint32_t>(flags) & kSecCodeSignatureAdhoc) {
    return base::unexpected(MissingRequirementReason::NoOrAdHocSignature);
  }

  // Time to start building a requirement that we will use to validate
  // another code signature. First let's get the framework bundle requirement.
  // We will build a suitable requirement based off that.
  base::apple::ScopedCFTypeRef<SecRequirementRef> framework_requirement;
  status =
      SecCodeCopyDesignatedRequirement(framework_code.get(), kSecCSDefaultFlags,
                                       framework_requirement.InitializeInto());
  if (status != errSecSuccess) {
    DumpOSStatusError(status, "SecCodeCopyDesignatedRequirement");
    return base::unexpected(MissingRequirementReason::Error);
  }

  base::apple::ScopedCFTypeRef<CFStringRef> framework_requirement_string;
  status =
      SecRequirementCopyString(framework_requirement.get(), kSecCSDefaultFlags,
                               framework_requirement_string.InitializeInto());
  if (status != errSecSuccess) {
    DumpOSStatusError(status, "SecRequirementCopyString");
    DumpOSStatusError(status, "SecCodeCopyDesignatedRequirement");
  }

  return framework_requirement_string;
}

base::apple::ScopedCFTypeRef<SecRequirementRef> RequirementFromString(
    CFStringRef requirement_string) {
  base::apple::ScopedCFTypeRef<SecRequirementRef> requirement;
  OSStatus status = SecRequirementCreateWithString(
      requirement_string, kSecCSDefaultFlags, requirement.InitializeInto());
  if (status != errSecSuccess) {
    DumpOSStatusError(status,
                      std::string("SecRequirementCreateWithString: ") +
                          base::SysCFStringRefToUTF8(requirement_string));
    return base::apple::ScopedCFTypeRef<SecRequirementRef>(nullptr);
  }

  return requirement;
}

}  // namespace apps