momo zone

调核人的blog

Category Archives: Uncategorized

Chrome ERR_CERTIFICATE_TRANSPARENCY_REQUIRED 问题根源

最近常常有人反映像baidu等网站的https报错,而且用的都是chrome浏览器,错误消息是:

ERR_CERTIFICATE_TRANSPARENCY_REQUIRED

看样子和证书透明审计有关系

chrome有相关返回值的有两处:

Net/socket/ssl_client_socket_impl.cc

Net/quic/chromium/crypto/proof_verifier_chromium.cc

两处的代码差不多,因为一般的站不涉及quic所以只看前者的代码

Net/socket/ssl_client_socket_impl.cc:

Int SSLClientSocketImpl::VerifyCT(){
......
  ct_verify_result_.cert_policy_compliance =
      policy_enforcer_->DoesConformToCertPolicy(
          server_cert_verify_result_.verified_cert.get(), verified_scts,
          net_log_);


  if (ct_verify_result_.cert_policy_compliance !=
          ct::CertPolicyCompliance::CERT_POLICY_COMPLIES_VIA_SCTS &&
      transport_security_state_->ShouldRequireCT(
          host_and_port_.host(), server_cert_verify_result_.verified_cert.get(),
          server_cert_verify_result_.public_key_hashes)) {
    server_cert_verify_result_.cert_status |=
        CERT_STATUS_CERTIFICATE_TRANSPARENCY_REQUIRED;
    return ERR_CERTIFICATE_TRANSPARENCY_REQUIRED;
  }
  return OK;
}

条件1和2决定了是否会出现ERR_CERTIFICATE_TRANSPARENCY_REQUIRED的错误。

先看条件1:

DoesConformToCertPolicy()在net/cert/ct_policy_enforcer.cc中定义:

ct::CertPolicyCompliance CTPolicyEnforcer::DoesConformToCertPolicy(
    X509Certificate* cert,
    const ct::SCTList& verified_scts,
    const NetLogWithSource& net_log) {
  // If the build is not timely, no certificate is considered compliant
  // with CT policy. The reasoning is that, for example, a log might
  // have been pulled and is no longer considered valid; thus, a client
  // needs up-to-date information about logs to consider certificates to
  // be compliant with policy.
  bool build_timely = IsBuildTimely();
  ct::CertPolicyCompliance compliance;
  if (!build_timely) {
    compliance = ct::CertPolicyCompliance::CERT_POLICY_BUILD_NOT_TIMELY;
  } else {
    compliance = CheckCertPolicyCompliance(*cert, verified_scts);
  }

  NetLog::ParametersCallback net_log_callback =
      base::Bind(&NetLogCertComplianceCheckResultCallback,
                 base::Unretained(cert), build_timely, compliance);

  net_log.AddEvent(NetLogEventType::CERT_CT_COMPLIANCE_CHECKED,
                   net_log_callback);

  return compliance;
}

这里IsBuildTimely()很关键:

// Returns true if the current build is recent enough to ensure that
// built-in security information (e.g. CT Logs) is fresh enough.
// TODO(eranm): Move to base or net/base
bool IsBuildTimely() {
  const base::Time build_time = base::GetBuildTime();
  // We consider built-in information to be timely for 10 weeks.
  return (base::Time::Now() - build_time).InDays() < 70 /* 10 weeks */;
}

如果当前版本是在70天前编译的那么compliance就返回CERT_POLICY_BUILD_NOT_TIMELY。当前版本是chrome34,确实超过70天了,那么条件1成立。

回过头来看看条件2:
ShouldRequiredCT在net/http/transport_security_state.cc定义:

bool TransportSecurityState::ShouldRequireCT(
    const std::string& hostname,
    const X509Certificate* validated_certificate_chain,
    const HashValueVector& public_key_hashes) {
  using CTRequirementLevel = RequireCTDelegate::CTRequirementLevel;

  CTRequirementLevel ct_required = CTRequirementLevel::DEFAULT;
  if (require_ct_delegate_)
    ct_required = require_ct_delegate_->IsCTRequiredForHost(hostname);
  if (ct_required != CTRequirementLevel::DEFAULT)
    return ct_required == CTRequirementLevel::REQUIRED;

  // Allow unittests to override the default result.
  if (g_ct_required_for_testing)
    return g_ct_required_for_testing == 1;

  // Until CT is required for all secure hosts on the Internet, this should
  // remain false. It is provided to simplify the various short-circuit
  // returns below.
  bool default_response = false;

// FieldTrials are not supported in Native Client apps.
#if !defined(OS_NACL)
  // Emergency escape valve; not to be activated until there's an actual
  // emergency (e.g. a weird path-building bug due to a CA's failed
  // disclosure of cross-signed sub-CAs).
  std::string group_name =
      base::FieldTrialList::FindFullName("EnforceCTForProblematicRoots");
  if (base::StartsWith(group_name, "disabled",
                       base::CompareCase::INSENSITIVE_ASCII)) {
    return default_response;
  }
#endif

  const base::Time epoch = base::Time::UnixEpoch();
  for (const auto& restricted_ca : kCTRequiredPolicies) {
    if (epoch + restricted_ca.effective_date >
        validated_certificate_chain->valid_start()) {
      // The candidate cert is not subject to the CT policy, because it
      // was issued before the effective CT date.
      continue;
    }

    for (const auto& hash : public_key_hashes) {
      if (hash.tag != HASH_VALUE_SHA256)
        continue;

      // Determine if |hash| is in the set of roots of |restricted_ca|.
      if (!std::binary_search(restricted_ca.roots,
                              restricted_ca.roots + restricted_ca.roots_length,
                              hash, SHA256ToHashValueComparator())) {
        continue;
      }

      // Found a match, indicating this certificate is potentially
      // restricted. Determine if any of the hashes are on the exclusion
      // list as exempt from the CT requirement.
      for (const auto& sub_ca_hash : public_key_hashes) {
        if (sub_ca_hash.tag != HASH_VALUE_SHA256)
          continue;
        if (std::binary_search(
                restricted_ca.exceptions,
                restricted_ca.exceptions + restricted_ca.exceptions_length,
                sub_ca_hash, SHA256ToHashValueComparator())) {
          // Found an excluded sub-CA; CT is not required.
          return default_response;
        }
      }

      // No exception found. This certificate must conform to the CT policy.
      return true;
    }
  }

  return default_response;
}

这里的kCTRequiredPolicies遍历是关键,它来自net/http/transport_security_state_ct_policies.inc:

const SHA256HashValue kSymantecRoots[] = {
    {{0x02, 0x3c, 0x81, 0xcc, 0xe8, 0xe7, 0xc6, 0x4f, 0xa9, 0x42, 0xd3,
      0xc1, 0x50, 0x48, 0x70, 0x7d, 0x35, 0xd9, 0xbb, 0x5b, 0x87, 0xf4,
      0xf5, 0x44, 0xc5, 0xbf, 0x1b, 0xc5, 0x64, 0x3a, 0xf2, 0xfa}},
    {{0x09, 0x99, 0xbf, 0x90, 0x0b, 0xd5, 0xc2, 0x97, 0x86, 0x5e, 0x21,
      0xe1, 0xaa, 0xde, 0x6c, 0xf6, 0xbb, 0x3a, 0x94, 0xd1, 0x1a, 0xe5,
      0xea, 0x79, 0x84, 0x42, 0xa4, 0xe2, 0xf8, 0x13, 0x24, 0x1f}},
    {{0x0b, 0xdd, 0x5a, 0xbe, 0x94, 0x0c, 0xaa, 0xab, 0xe8, 0xb2, 0xbb,
      0xa8, 0x83, 0x48, 0xfb, 0x6f, 0x4a, 0xa4, 0xcc, 0x84, 0x43, 0x6f,
      0x88, 0x0b, 0xec, 0xe6, 0x6b, 0x48, 0xbd, 0xa9, 0x13, 0xd8}},
    {{0x16, 0xa9, 0xe0, 0x12, 0xd3, 0x23, 0x29, 0xf2, 0x82, 0xb1, 0x0b,
      0xbf, 0x57, 0xc7, 0xc0, 0xb4, 0x2a, 0xe8, 0x0f, 0x6a, 0xc9, 0x54,
      0x2e, 0xb4, 0x09, 0xbc, 0x1c, 0x2c, 0xde, 0x50, 0xd3, 0x22}},
    {{0x17, 0x75, 0x5a, 0x5c, 0x29, 0x5f, 0x3d, 0x2d, 0x72, 0xe6, 0xf0,
      0x31, 0xa1, 0xf0, 0x7f, 0x40, 0x0c, 0x58, 0x8b, 0x9e, 0x58, 0x2b,
      0x22, 0xf1, 0x7e, 0xae, 0x31, 0xa1, 0x59, 0x0d, 0x11, 0x85}},
    {{0x19, 0x06, 0xc6, 0x12, 0x4d, 0xbb, 0x43, 0x85, 0x78, 0xd0, 0x0e,
      0x06, 0x6d, 0x50, 0x54, 0xc6, 0xc3, 0x7f, 0x0f, 0xa6, 0x02, 0x8c,
      0x05, 0x54, 0x5e, 0x09, 0x94, 0xed, 0xda, 0xec, 0x86, 0x29}},
    {{0x19, 0x16, 0xf3, 0x50, 0x8e, 0xc3, 0xfa, 0xd7, 0x95, 0xf8, 0xdc,
      0x4b, 0xd3, 0x16, 0xf9, 0xc6, 0x08, 0x5a, 0x64, 0xde, 0x3c, 0x41,
      0x53, 0xac, 0x6d, 0x62, 0xd5, 0xea, 0x19, 0x51, 0x5d, 0x39}},
    {{0x1d, 0x75, 0xd0, 0x83, 0x1b, 0x9e, 0x08, 0x85, 0x39, 0x4d, 0x32,
      0xc7, 0xa1, 0xbf, 0xdb, 0x3d, 0xbc, 0x1c, 0x28, 0xe2, 0xb0, 0xe8,
      0x39, 0x1f, 0xb1, 0x35, 0x98, 0x1d, 0xbc, 0x5b, 0xa9, 0x36}},
    {{0x22, 0x07, 0x6e, 0x5a, 0xef, 0x44, 0xbb, 0x9a, 0x41, 0x6a, 0x28,
      0xb7, 0xd1, 0xc4, 0x43, 0x22, 0xd7, 0x05, 0x9f, 0x60, 0xfe, 0xff,
      0xa5, 0xca, 0xf6, 0xc5, 0xbe, 0x84, 0x47, 0x89, 0x13, 0x03}},
    {{0x25, 0xb4, 0x1b, 0x50, 0x6e, 0x49, 0x30, 0x95, 0x28, 0x23, 0xa6,
      0xeb, 0x9f, 0x1d, 0x31, 0xde, 0xf6, 0x45, 0xea, 0x38, 0xa5, 0xc6,
      0xc6, 0xa9, 0x6d, 0x71, 0x95, 0x7e, 0x38, 0x4d, 0xf0, 0x58}},
    {{0x26, 0xc1, 0x8d, 0xc6, 0xee, 0xa6, 0xf6, 0x32, 0xf6, 0x76, 0xbc,
      0xeb, 0xa1, 0xd8, 0xc2, 0xb4, 0x83, 0x52, 0xf2, 0x9c, 0x2d, 0x5f,
      0xcd, 0xa8, 0x78, 0xe0, 0x9d, 0xcb, 0x83, 0x2d, 0xd6, 0xe5}},
    {{0x2d, 0xc9, 0x47, 0x0b, 0xe6, 0x3e, 0xf4, 0xac, 0xf1, 0xbd, 0x82,
      0x86, 0x09, 0x40, 0x2b, 0xb7, 0xb8, 0x7b, 0xd9, 0x96, 0x38, 0xa6,
      0x43, 0x93, 0x4e, 0x88, 0x68, 0x2d, 0x1b, 0xe8, 0xc3, 0x08}},
    {{0x2d, 0xee, 0x51, 0x71, 0x59, 0x6a, 0xb8, 0xf3, 0xcd, 0x3c, 0x76,
      0x35, 0xfe, 0xa8, 0xe6, 0xc3, 0x00, 0x6a, 0xa9, 0xe3, 0x1d, 0xb3,
      0x9d, 0x03, 0xa7, 0x48, 0x0d, 0xdb, 0x24, 0x28, 0xa3, 0x3e}},
    {{0x30, 0x27, 0xa2, 0x98, 0xfa, 0x57, 0x31, 0x4d, 0xc0, 0xe3, 0xdd,
      0x10, 0x19, 0x41, 0x1b, 0x8f, 0x40, 0x4c, 0x43, 0xc3, 0xf9, 0x34,
      0xce, 0x3b, 0xdf, 0x85, 0x65, 0x12, 0xc8, 0x0a, 0xa1, 0x5c}},
    {{0x31, 0x51, 0x26, 0x80, 0x23, 0x3f, 0x5f, 0x2a, 0x1f, 0x29, 0x43,
      0x7f, 0x56, 0xd4, 0x98, 0x8c, 0xf0, 0xaf, 0xc4, 0x1c, 0xc6, 0xc5,
      0xda, 0x62, 0x75, 0x92, 0x8e, 0x9c, 0x0b, 0xea, 0xde, 0x27}},
    {{0x43, 0xb3, 0x10, 0x7d, 0x73, 0x42, 0x16, 0x5d, 0x40, 0x6c, 0xf9,
      0x75, 0xcd, 0x79, 0xb3, 0x6e, 0xd1, 0x64, 0x50, 0x48, 0xf0, 0x5d,
      0x7f, 0xf6, 0xea, 0x00, 0x96, 0xe4, 0x27, 0xb7, 0xdb, 0x84}},
    {{0x46, 0x3d, 0xbb, 0x9b, 0x0a, 0x26, 0xed, 0x26, 0x16, 0x39, 0x7b,
      0x64, 0x31, 0x25, 0xfb, 0xd2, 0x9b, 0x66, 0xcf, 0x3a, 0x46, 0xfd,
      0xb4, 0x38, 0x4b, 0x20, 0x9e, 0x78, 0x23, 0x7a, 0x1a, 0xff}},
    {{0x47, 0x9d, 0x13, 0x0b, 0xf3, 0xfc, 0x61, 0xdc, 0x2f, 0x1d, 0x50,
      0x8d, 0x23, 0x9a, 0x13, 0x27, 0x6a, 0xe7, 0xb3, 0xc9, 0x84, 0x10,
      0x11, 0xa0, 0x2c, 0x14, 0x02, 0xc7, 0xe6, 0x77, 0xbd, 0x5f}},
    {{0x49, 0x05, 0x46, 0x66, 0x23, 0xab, 0x41, 0x78, 0xbe, 0x92, 0xac,
      0x5c, 0xbd, 0x65, 0x84, 0xf7, 0xa1, 0xe1, 0x7f, 0x27, 0x65, 0x2d,
      0x5a, 0x85, 0xaf, 0x89, 0x50, 0x4e, 0xa2, 0x39, 0xaa, 0xaa}},
    {{0x49, 0x5a, 0x96, 0xba, 0x6b, 0xad, 0x78, 0x24, 0x07, 0xbd, 0x52,
      0x1a, 0x00, 0xba, 0xce, 0x65, 0x7b, 0xb3, 0x55, 0x55, 0x5e, 0x4b,
      0xb7, 0xf8, 0x14, 0x6c, 0x71, 0xbb, 0xa5, 0x7e, 0x7a, 0xce}},
    {{0x4b, 0xa6, 0x03, 0x1c, 0xa3, 0x05, 0xb0, 0x9e, 0x53, 0xbd, 0xe3,
      0x70, 0x51, 0x45, 0x48, 0x1d, 0x03, 0x32, 0xb6, 0x51, 0xfe, 0x30,
      0x37, 0x0d, 0xd5, 0x25, 0x4c, 0xc4, 0xd2, 0xcb, 0x32, 0xf3}},
    {{0x51, 0x92, 0x43, 0x8e, 0xc3, 0x69, 0xd7, 0xee, 0x0c, 0xe7, 0x1f,
      0x5c, 0x6d, 0xb7, 0x5f, 0x94, 0x1e, 0xfb, 0xf7, 0x2e, 0x58, 0x44,
      0x17, 0x15, 0xe9, 0x9e, 0xab, 0x04, 0xc2, 0xc8, 0xac, 0xee}},
    {{0x56, 0x7b, 0x82, 0x11, 0xfd, 0x20, 0xd3, 0xd2, 0x83, 0xee, 0x0c,
      0xd7, 0xce, 0x06, 0x72, 0xcb, 0x9d, 0x99, 0xbc, 0x5b, 0x48, 0x7a,
      0x58, 0xc9, 0xd5, 0x4e, 0xc6, 0x7f, 0x77, 0xd4, 0xa8, 0xf5}},
    {{0x5c, 0x4f, 0x28, 0x53, 0x88, 0xf3, 0x83, 0x36, 0x26, 0x9a, 0x55,
      0xc7, 0xc1, 0x2c, 0x0b, 0x3c, 0xa7, 0x3f, 0xef, 0x2a, 0x5a, 0x4d,
      0xf8, 0x2b, 0x89, 0x14, 0x1e, 0x84, 0x1a, 0x6c, 0x4d, 0xe4}},
    {{0x67, 0xdc, 0x4f, 0x32, 0xfa, 0x10, 0xe7, 0xd0, 0x1a, 0x79, 0xa0,
      0x73, 0xaa, 0x0c, 0x9e, 0x02, 0x12, 0xec, 0x2f, 0xfc, 0x3d, 0x77,
      0x9e, 0x0a, 0xa7, 0xf9, 0xc0, 0xf0, 0xe1, 0xc2, 0xc8, 0x93}},
    {{0x6b, 0x86, 0xde, 0x96, 0xa6, 0x58, 0xa5, 0x68, 0x20, 0xa4, 0xf3,
      0x5d, 0x90, 0xdb, 0x6c, 0x3e, 0xfd, 0xd5, 0x74, 0xce, 0x94, 0xb9,
      0x09, 0xcb, 0x0d, 0x7f, 0xf1, 0x7c, 0x3c, 0x18, 0x9d, 0x83}},
    {{0x70, 0x06, 0xa3, 0x83, 0x11, 0xe5, 0x8f, 0xb1, 0x93, 0x48, 0x42,
      0x33, 0x21, 0x82, 0x10, 0xc6, 0x61, 0x25, 0xa0, 0xe4, 0xa8, 0x26,
      0xae, 0xd5, 0x39, 0xac, 0x56, 0x1d, 0xfb, 0xfb, 0xd9, 0x03}},
    {{0x78, 0x1f, 0x1c, 0x3a, 0x6a, 0x42, 0xe3, 0xe9, 0x15, 0x22, 0x2d,
      0xb4, 0x96, 0x77, 0x02, 0xa2, 0xe5, 0x77, 0xae, 0xb0, 0x17, 0x07,
      0x5f, 0xa3, 0xc1, 0x59, 0x85, 0x1f, 0xdd, 0xd0, 0x53, 0x5e}},
    {{0x7c, 0xaa, 0x03, 0x46, 0x51, 0x24, 0x59, 0x0c, 0x60, 0x1e, 0x56,
      0x7e, 0x52, 0x14, 0x8e, 0x95, 0x2c, 0x0c, 0xff, 0xe8, 0x90, 0x00,
      0x53, 0x0f, 0xe0, 0xd9, 0x5b, 0x6d, 0x50, 0xea, 0xae, 0x41}},
    {{0x80, 0x9f, 0x2b, 0xaa, 0xe3, 0x5a, 0xfb, 0x4f, 0x36, 0xbd, 0x64,
      0x76, 0xce, 0x75, 0xc2, 0x00, 0x10, 0x77, 0x90, 0x1b, 0x6a, 0xf5,
      0xc4, 0xda, 0xb8, 0x2e, 0x18, 0x8c, 0x6b, 0x95, 0xc1, 0xa1}},
    {{0x81, 0xa9, 0x8f, 0xc7, 0x88, 0xc3, 0x5f, 0x55, 0x76, 0x45, 0xa9,
      0x52, 0x24, 0xe5, 0x0c, 0xd1, 0xda, 0xc8, 0xff, 0xb2, 0x09, 0xdc,
      0x1e, 0x56, 0x88, 0xaa, 0x29, 0x20, 0x5f, 0x13, 0x22, 0x18}},
    {{0x86, 0x0a, 0x7f, 0x19, 0x21, 0x0d, 0x5e, 0xad, 0x05, 0x7a, 0x78,
      0x53, 0x2b, 0x80, 0x95, 0x14, 0x53, 0xcb, 0x29, 0x07, 0x31, 0x5f,
      0x3b, 0xa7, 0xaa, 0x47, 0xb6, 0x98, 0x97, 0xd7, 0x0f, 0x3f}},
    {{0x87, 0xaf, 0x34, 0xd6, 0x6f, 0xb3, 0xf2, 0xfd, 0xf3, 0x6e, 0x09,
      0x11, 0x1e, 0x9a, 0xba, 0x2f, 0x6f, 0x44, 0xb2, 0x07, 0xf3, 0x86,
      0x3f, 0x3d, 0x0b, 0x54, 0xb2, 0x50, 0x23, 0x90, 0x9a, 0xa5}},
    {{0x95, 0x73, 0x54, 0x73, 0xbd, 0x67, 0xa3, 0xb9, 0x5a, 0x8d, 0x5f,
      0x90, 0xc5, 0xa2, 0x1a, 0xce, 0x1e, 0x0d, 0x79, 0x47, 0x32, 0x06,
      0x74, 0xd4, 0xab, 0x84, 0x79, 0x72, 0xb9, 0x15, 0x44, 0xd2}},
    {{0x96, 0x7b, 0x0c, 0xd9, 0x3f, 0xce, 0xf7, 0xf2, 0x7c, 0xe2, 0xc2,
      0x45, 0x76, 0x7a, 0xe9, 0xb0, 0x5a, 0x77, 0x6b, 0x06, 0x49, 0xf9,
      0x96, 0x5b, 0x62, 0x90, 0x96, 0x84, 0x69, 0x68, 0x68, 0x72}},
    {{0x96, 0x99, 0x22, 0x5c, 0x5d, 0xe5, 0x2e, 0x56, 0xcd, 0xd3, 0x2d,
      0xf2, 0xe9, 0x6d, 0x1c, 0xfe, 0xa5, 0xaa, 0x3c, 0xa0, 0xbb, 0x52,
      0xcd, 0x89, 0x33, 0xc2, 0x3b, 0x5c, 0x27, 0x44, 0x38, 0x20}},
    {{0x9c, 0x6f, 0x6a, 0x12, 0x3c, 0xba, 0xa4, 0xee, 0x34, 0xdb, 0xec,
      0xee, 0xe2, 0x4c, 0x97, 0xd7, 0x38, 0x87, 0x8c, 0xb4, 0x23, 0xf3,
      0xc2, 0x27, 0x39, 0x03, 0x42, 0x4f, 0x5d, 0x1f, 0x6d, 0xd5}},
    {{0xa6, 0xf1, 0xf9, 0xbf, 0x8a, 0x0a, 0x9d, 0xdc, 0x08, 0x0f, 0xb4,
      0x9b, 0x1e, 0xfc, 0x3d, 0x1a, 0x1c, 0x2c, 0x32, 0xdc, 0x0e, 0x13,
      0x6a, 0x5b, 0x00, 0xc9, 0x73, 0x16, 0xf2, 0xa3, 0xdc, 0x11}},
    {{0xab, 0x38, 0x76, 0xc3, 0xda, 0x5d, 0xe0, 0xc9, 0xcf, 0x67, 0x36,
      0x86, 0x8e, 0xe5, 0xb8, 0x8b, 0xf9, 0xba, 0x1d, 0xff, 0x9c, 0x9d,
      0x72, 0xd2, 0xfe, 0x5a, 0x8d, 0x2f, 0x78, 0x30, 0x21, 0x66}},
    {{0xab, 0x39, 0xa4, 0xb0, 0x25, 0x95, 0x56, 0x91, 0xa4, 0x02, 0x69,
      0xf3, 0x53, 0xfa, 0x1d, 0x5c, 0xb9, 0x4e, 0xaf, 0x6c, 0x7e, 0xa9,
      0x80, 0x84, 0x84, 0xbb, 0xbb, 0x62, 0xfd, 0x9f, 0x68, 0xf3}},
    {{0xab, 0x5c, 0xdb, 0x33, 0x56, 0x39, 0x73, 0x56, 0xd6, 0xe6, 0x91,
      0x97, 0x3c, 0x25, 0xb8, 0x61, 0x8b, 0x65, 0xd7, 0x6a, 0x90, 0x48,
      0x6e, 0xa7, 0xa8, 0xa5, 0xc1, 0x77, 0x67, 0xf4, 0x67, 0x3a}},
    {{0xab, 0x98, 0x49, 0x52, 0x76, 0xad, 0xf1, 0xec, 0xaf, 0xf2, 0x8f,
      0x35, 0xc5, 0x30, 0x48, 0x78, 0x1e, 0x5c, 0x17, 0x18, 0xda, 0xb9,
      0xc8, 0xe6, 0x7a, 0x50, 0x4f, 0x4f, 0x6a, 0x51, 0x32, 0x8f}},
    {{0xac, 0xf6, 0x5e, 0x1d, 0x62, 0xcb, 0x58, 0xa2, 0xba, 0xfd, 0x6f,
      0xfa, 0xb4, 0x0f, 0xb8, 0x86, 0x99, 0xc4, 0x73, 0x97, 0xcf, 0x5c,
      0xb4, 0x83, 0xd4, 0x2d, 0x69, 0xca, 0xd3, 0x4c, 0xd4, 0x8b}},
    {{0xaf, 0x20, 0x7c, 0x61, 0xfd, 0x9c, 0x7c, 0xf9, 0x2c, 0x2a, 0xfe,
      0x81, 0x54, 0x28, 0x2d, 0xc3, 0xf2, 0xcb, 0xf3, 0x2f, 0x75, 0xcd,
      0x17, 0x28, 0x14, 0xc5, 0x2b, 0x03, 0xb7, 0xeb, 0xc2, 0x58}},
    {{0xb1, 0x12, 0x41, 0x42, 0xa5, 0xa1, 0xa5, 0xa2, 0x88, 0x19, 0xc7,
      0x35, 0x34, 0x0e, 0xff, 0x8c, 0x9e, 0x2f, 0x81, 0x68, 0xfe, 0xe3,
      0xba, 0x18, 0x7f, 0x25, 0x3b, 0xc1, 0xa3, 0x92, 0xd7, 0xe2}},
    {{0xb2, 0xde, 0xf5, 0x36, 0x2a, 0xd3, 0xfa, 0xcd, 0x04, 0xbd, 0x29,
      0x04, 0x7a, 0x43, 0x84, 0x4f, 0x76, 0x70, 0x34, 0xea, 0x48, 0x92,
      0xf8, 0x0e, 0x56, 0xbe, 0xe6, 0x90, 0x24, 0x3e, 0x25, 0x02}},
    {{0xbc, 0xfb, 0x44, 0xaa, 0xb9, 0xad, 0x02, 0x10, 0x15, 0x70, 0x6b,
      0x41, 0x21, 0xea, 0x76, 0x1c, 0x81, 0xc9, 0xe8, 0x89, 0x67, 0x59,
      0x0f, 0x6f, 0x94, 0xae, 0x74, 0x4d, 0xc8, 0x8b, 0x78, 0xfb}},
    {{0xc0, 0x71, 0x35, 0xf6, 0xb4, 0x52, 0x39, 0x82, 0x64, 0xa4, 0x77,
      0x6d, 0xbd, 0x0a, 0x6a, 0x30, 0x7c, 0x60, 0xa3, 0x6f, 0x96, 0x7b,
      0xd2, 0x63, 0x21, 0xdc, 0xb8, 0x17, 0xb5, 0xc0, 0xc4, 0x81}},
    {{0xca, 0xb4, 0x82, 0xcd, 0x3e, 0x82, 0x0c, 0x5c, 0xe7, 0x2a, 0xa3,
      0xb6, 0xfd, 0xbe, 0x98, 0x8b, 0xb8, 0xa4, 0xf0, 0x40, 0x7e, 0xca,
      0xfd, 0x8c, 0x92, 0x6e, 0x36, 0x82, 0x4e, 0xab, 0x92, 0xdd}},
    {{0xd2, 0xf9, 0x1a, 0x04, 0xe3, 0xa6, 0x1d, 0x4e, 0xad, 0x78, 0x48,
      0xc8, 0xd4, 0x3b, 0x5e, 0x11, 0x52, 0xd8, 0x85, 0x72, 0x74, 0x89,
      0xbc, 0x65, 0x73, 0x8b, 0x67, 0xc0, 0xa2, 0x27, 0x85, 0xa7}},
    {{0xd3, 0xa2, 0x5d, 0xa8, 0x0d, 0xb7, 0xba, 0xb1, 0x29, 0xa0, 0x66,
      0xab, 0x41, 0x50, 0x3d, 0xdd, 0xff, 0xa0, 0x2c, 0x76, 0x8c, 0x05,
      0x89, 0xf9, 0x9f, 0xd7, 0x11, 0x93, 0xe6, 0x99, 0x16, 0xb6}},
    {{0xd4, 0xaf, 0x6c, 0x0a, 0x48, 0x23, 0x10, 0xbd, 0x7c, 0x54, 0xbb,
      0x7a, 0xb1, 0x21, 0x91, 0x6f, 0x86, 0xc0, 0xc0, 0x7c, 0xd5, 0x2f,
      0xca, 0xc3, 0x2d, 0x38, 0x44, 0xc2, 0x60, 0x05, 0x11, 0x5f}},
    {{0xda, 0x80, 0x0b, 0x80, 0xb2, 0xa8, 0x7d, 0x39, 0x9e, 0x66, 0xfa,
      0x19, 0xd7, 0x2f, 0xdf, 0x49, 0x98, 0x3b, 0x47, 0xd8, 0xcf, 0x32,
      0x2c, 0x7c, 0x79, 0x50, 0x3a, 0x0c, 0x7e, 0x28, 0xfe, 0xaf}},
    {{0xf1, 0x5f, 0x1d, 0x32, 0x3e, 0xd9, 0xca, 0x98, 0xe9, 0xea, 0x95,
      0xb3, 0x3e, 0xc5, 0xdd, 0xa4, 0x7e, 0xa4, 0xc3, 0x29, 0xf9, 0x52,
      0xc1, 0x6f, 0x65, 0xad, 0x41, 0x9e, 0x64, 0x52, 0x04, 0x76}},
    {{0xf2, 0xe9, 0x36, 0x5e, 0xa1, 0x21, 0xdf, 0x5e, 0xeb, 0xd8, 0xde,
      0x24, 0x68, 0xfd, 0xc1, 0x71, 0xdc, 0x0a, 0x9e, 0x46, 0xda, 0xdc,
      0x1a, 0xb4, 0x1d, 0x52, 0x79, 0x0b, 0xa9, 0x80, 0xa7, 0xc2}},
    {{0xf5, 0x3c, 0x22, 0x05, 0x98, 0x17, 0xdd, 0x96, 0xf4, 0x00, 0x65,
      0x16, 0x39, 0xd2, 0xf8, 0x57, 0xe2, 0x10, 0x70, 0xa5, 0x9a, 0xbe,
      0xd9, 0x07, 0x94, 0x00, 0xd9, 0xf6, 0x95, 0x50, 0x69, 0x00}},
    {{0xf6, 0xb5, 0x9c, 0x8e, 0x27, 0x89, 0xa1, 0xfd, 0x5d, 0x5b, 0x25,
      0x37, 0x42, 0xfe, 0xad, 0xc6, 0x92, 0x5c, 0xb9, 0x3e, 0xdc, 0x34,
      0x5e, 0x53, 0x16, 0x6e, 0x12, 0xc5, 0x2b, 0xa2, 0xa6, 0x01}},
    {{0xff, 0x56, 0x80, 0xcd, 0x73, 0xa5, 0x70, 0x3d, 0xa0, 0x48, 0x17,
      0xa0, 0x75, 0xfd, 0x46, 0x25, 0x06, 0xa7, 0x35, 0x06, 0xc4, 0xb8,
      0x1a, 0x15, 0x83, 0xef, 0x54, 0x94, 0x78, 0xd2, 0x64, 0x76}},
};

const SHA256HashValue kSymantecExceptions[] = {
    {{0x56, 0xe9, 0x8d, 0xea, 0xc0, 0x06, 0xa7, 0x29, 0xaf, 0xa2, 0xed,
      0x79, 0xf9, 0xe4, 0x19, 0xdf, 0x69, 0xf4, 0x51, 0x24, 0x25, 0x96,
      0xd2, 0xaa, 0xf2, 0x84, 0xc7, 0x4a, 0x85, 0x5e, 0x35, 0x2e}},
    {{0x72, 0x89, 0xc0, 0x6d, 0xed, 0xd1, 0x6b, 0x71, 0xa7, 0xdc, 0xca,
      0x66, 0x57, 0x85, 0x72, 0xe2, 0xe1, 0x09, 0xb1, 0x1d, 0x70, 0xad,
      0x04, 0xc2, 0x60, 0x1b, 0x67, 0x43, 0xbc, 0x66, 0xd0, 0x7b}},
    {{0xa5, 0x3d, 0xb6, 0x10, 0x6b, 0xb7, 0x60, 0x35, 0x4c, 0xed, 0x90,
      0x45, 0xfb, 0x06, 0xeb, 0x06, 0xaf, 0x85, 0xe6, 0xb1, 0x18, 0xc0,
      0x62, 0xed, 0x13, 0xc3, 0x05, 0x1d, 0xfe, 0xb8, 0xd4, 0x9c}},
    {{0xb5, 0xcf, 0x82, 0xd4, 0x7e, 0xf9, 0x82, 0x3f, 0x9a, 0xa7, 0x8f,
      0x12, 0x31, 0x86, 0xc5, 0x2e, 0x88, 0x79, 0xea, 0x84, 0xb0, 0xf8,
      0x22, 0xc9, 0x1d, 0x83, 0xe0, 0x42, 0x79, 0xb7, 0x8f, 0xd5}},
    {{0xc0, 0x55, 0x4b, 0xde, 0x87, 0xa0, 0x75, 0xec, 0x13, 0xa6, 0x1f,
      0x27, 0x59, 0x83, 0xae, 0x02, 0x39, 0x57, 0x29, 0x4b, 0x45, 0x4c,
      0xaf, 0x0a, 0x97, 0x24, 0xe3, 0xb2, 0x1b, 0x79, 0x35, 0xbc}},
    {{0xe2, 0x4f, 0x8e, 0x8c, 0x21, 0x85, 0xda, 0x2f, 0x5e, 0x88, 0xd4,
      0x57, 0x9e, 0x81, 0x7c, 0x47, 0xbf, 0x6e, 0xaf, 0xbc, 0x85, 0x05,
      0xf0, 0xf9, 0x60, 0xfd, 0x5a, 0x0d, 0xf4, 0x47, 0x3a, 0xd3}},
    {{0xec, 0x72, 0x29, 0x69, 0xcb, 0x64, 0x20, 0x0a, 0xb6, 0x63, 0x8f,
      0x68, 0xac, 0x53, 0x8e, 0x40, 0xab, 0xab, 0x5b, 0x19, 0xa6, 0x48,
      0x56, 0x61, 0x04, 0x2a, 0x10, 0x61, 0xc4, 0x61, 0x27, 0x76}},
    {{0xfa, 0xe4, 0x60, 0x00, 0xd8, 0xf7, 0x04, 0x25, 0x58, 0x54, 0x1e,
      0x98, 0xac, 0xf3, 0x51, 0x27, 0x95, 0x89, 0xf8, 0x3b, 0x6d, 0x30,
      0x01, 0xc1, 0x84, 0x42, 0xe4, 0x40, 0x3d, 0x11, 0x18, 0x49}},
};

const CTRequiredPolicy kCTRequiredPolicies[] = {
    {
        kSymantecRoots, arraysize(kSymantecRoots),
        // 1 June 2016, 00:00:00 GMT.
        base::TimeDelta::FromSeconds(1464739200), kSymantecExceptions,
        arraysize(kSymantecExceptions),
    },
};

判定签发证书的CA公钥的sha-256是不是在transport_security_state_ct_policies.inc里面,而这个文件中写明了都是symantech的证书。

现在明白了,条件2就是如果服务器证书由symantech签发(不包含在exception中的)。不幸的是百度符合条件。其实准确的说,并不是仅symantech的证书,还包含旗下的GeoTrust,verisign,thawte,估计大部分的证书都是由这些机构签发的,这下影响范围大了。 具体可以看net/data/ssl/symantec/README.md,其中这个链接说明了为什么symantech有如此“优待”:

http://security.googleblog.com/2015/10/sustaining-digital-certificate-security.html 意思是symantech之前的审核不严,被google通过CT查出了问题,于是从2016年1月1日开始给symantech戴紧箍咒,要求所有签发的证书都必须有CT,chromium的commit C77495f99。

总的说,返回这个错误的条件是:服务器证书带CT且当前chrome版本编译于70天前且证书是由symantech及其旗下的机构签发。

那么那个神秘的70天又是什么?

原来CT的信息SCT是有时效的,SCT同样由Ctlogger签发,和证书一样都是一个validBegin和validEnd,但SCT的签发公钥在证书有效期内很可能是会变化的(当然用户访问https站点时SCT也会是新的),对于chrome而言就是net/cert/ct_known_logs_static-inc.h中的key。而70天一般就是chrome发新版的周期,所以google的意思是要你保持chrome更新。

有人在chromium提的bug:

https://bugs.chromium.org/p/chromium/issues/detail?id=664177

将70天的检查改成了fail-open,也就是70天过了白过。

Advertisements

Chromium/chrome开启OCSP和CRL验证以及hard-fail

Chrome/chromium 对于证书,默认并不验证OCSP或CRL,而是自己的CRLSet,可以简单的理解为精选的CRL。

有一篇文章对CRLSet进行了深入剖析:

https://www.grc.com/revocation/crlsets.html

 

这篇文章认为CRLSet的最大问题是其中包含的吊销信息太少,极端情况下只占主流CRL吊销信息的2%。抛开CRL和CRLSet,个人感觉OCSP已经取代了CRL,比如证书如果支持OCSP就先查询它,那为什么chrome不打开OCSP验证呢?chrome的说法是OCSP机制是broken的,我在后面的一些体验让我有点认同这种观点。

 

开启OCSP和CRL验证需要对chrome/chromium的策略进行编辑,而不是启动选项或flags

 

Chromium:

建立目录/etc/chromium/policies/managed 和/etc/chromium/policies/recommended

编辑/etc/chromium/policies/managed/my_policy.json:

{

“RequiredOnlineRevocationChecksForLocalAnchors”: true,

“EnableOnlineRevocationChecks”: true

}

 

Chrome:

和上面一样,但建立的目录改成/etc/opt/chrome/policies/managed 和/etc/opt/chrome/policies/recommended

 

 

重启,这样就会开启CRL和OCSP的验证,chrome访问会有如下行为:

访问SSL站慢了很多,因为要验证证书

如果ocsp无法访问,则使用crl

即使网站提供ocsp-stapling , chrome仍然请求ocsp和crt

如果ocsp和crl联系不上,且没有stapling,则EV降级为DV,DV则一直视为有效。 =>   soft-fail

如果有stapling 则还要看stapling

 

如果要实现hard-fail,即如果CRL,OCSP服务器联系不上也判证书吊销,则需要修改net/cert/cert_verify_proc_nss.cc:

Int CertVerifyProcNSS::VerifyInternalImpl(…….){

 

………

Status=PKIXVerifyCert(cert_handle, true, false, cert_io_enabled, NULL, 0, trust_anchors.get(), &crlset_callback, cvout);

 

………..

}

 

将其中那个false改成true:

Status=PKIXVerifyCert(cert_handle, true, true, cert_io_enabled, NULL, 0, trust_anchors.get(), &crlset_callback, cvout);

 

 

 

重新编译,然后访问几个ssl站,发现某个之前正常的ssl站提示证书已吊销!该证书由letsencrypt签发。用ssllab检查,发现证书未吊销,但提示 OCSP ERROR: OCSP response expired   ,相关解释在 https://community.qualys.com/thread/16460

我抓包看了下,发现确实OCSP应答的nextupdate 和ssllab提示的一样,已经过期。 我感觉是letsencrypt的问题,然后就上推问一问,结果确实是这样,ocsp.int-x3.letsencrypt.org 被告知故障,两天以后才彻底恢复。

 

也就是说如果采用hard-fail模式,那么OCSP将成为单点故障。如果采用soft-fail那么还要OCSP何用? 所以chrome干脆就不用OCSP了。 这也就是为什么之前的globalsign的证书吊销事故没有影响到chrome用户的原因。 这样用户体验是好了,可是怎么对得起“最安全浏览器”的称号呢?

一道C题

#include<sdtio.h>  

int main(void)
{
    unsigned char a = 0xa5;
    printf("%d\n",~a);
    char b = ~a;
    printf("%d\n",b);
    unsigned char c = ~a;
    printf("%d\n",c);

    return 0;
}  



看起来很简单,大多数人的答案是90,90,90。但正确答案是-166,90,90 出乎意料,第一个竟然是负数。关键在于那个取反 ~a,先反汇编看一下:

    unsigned char a = 0xa5;
 8048446:       c6 44 24 1f a5          movb   $0xa5,0x1f(%esp)
    printf("%d\n",~a);
 804844b:       0f b6 44 24 1f          movzbl 0x1f(%esp),%eax
 8048450:       f7 d0                   not    %eax
 8048452:       89 44 24 04             mov    %eax,0x4(%esp)
 8048456:       c7 04 24 40 85 04 08    movl   $0x8048540,(%esp)
 804845d:       e8 ae fe ff ff          call   8048310 <printf@plt>
    char b = ~a;
 8048462:       0f b6 44 24 1f          movzbl 0x1f(%esp),%eax
 8048467:       f7 d0                   not    %eax
 8048469:       88 44 24 1e             mov    %al,0x1e(%esp)
    printf("%d\n",b);
 804846d:       0f be 44 24 1e          movsbl 0x1e(%esp),%eax
 8048472:       89 44 24 04             mov    %eax,0x4(%esp)
 8048476:       c7 04 24 40 85 04 08    movl   $0x8048540,(%esp)
 804847d:       e8 8e fe ff ff          call   8048310 <printf@plt>
    unsigned char c = ~a;
 8048482:       0f b6 44 24 1f          movzbl 0x1f(%esp),%eax
 8048487:       f7 d0                   not    %eax
 8048489:       88 44 24 1d             mov    %al,0x1d(%esp)
    printf("%d\n",c);
 804848d:       0f b6 44 24 1d          movzbl 0x1d(%esp),%eax
 8048492:       89 44 24 04             mov    %eax,0x4(%esp)
 8048496:       c7 04 24 40 85 04 08    movl   $0x8048540,(%esp)
 804849d:       e8 6e fe ff ff          call   8048310 <printf@plt>

取反指令是NOT ,对于32位平台,NOT后面可以操作8位,16位,32位寄存器或地址,但gcc编译出来的代码都是操作32位的,而不管栈上面的那个变量类型。也就说凡是对短于32的变量取反,内存里面的最高为肯定是1,格式化输出有符号数的结果肯定是负数。上例中的也就是0x5a => 0xffffffa5,再套上printf的转换反码加1 为-0x5b=-166

对于64位平台(也就是跑64模式的cpu),NOT后面可以操作8位,16位,32位,64位寄存器或地址,但不同的是8位里面AH,BH,CH,DH寄存器不能访问。而且同32位平台一样,gcc编译出来的还是访问32位的寄存器或地址。所以结果还是-166

权威解释可以看intel的指令手册3B

为什么gcc会这样生成代码?我瞎猜一下gcc为了偷懒把x86的短于64位的取反做一个通用处理,一律用32位来搞?

ipv6 … some misunderstand

ipv6最大的缺陷在于不能向下兼容(并不是指NAT64或v4隧道)。但实际上缺陷在ipv4,ipv4无法向前兼容,因为没有地方往里面塞入其他信息来与其他非v4的端点通信。ipv4之所以地址是32位是因为他是一个“测试版本”,而有128位地址的ipv6是一个“生产版本” (IPv4’s 32-bit address length is because IPv4 is the “test version” of the Internet Protocol, and the production version (IPv6) has a more useful 128-bit address length.  —Vint Cerf, the father—or one of the fathers, anyway—of the internet and the IPv4 protocol)

广大**对反kongbu筏的意见

再苦不能苦SS,再穷不能穷VPN

Git process … Uh


letsencrypt免费证书

概念

Letsencrypt是一个免费的CA,它的出现标志着SSL/TLS加密的普及和互联网内容的加密将成为标准配置(mozilla之前曾宣称要逐步淘汰http)。它由互联网安全研究小组(ISRG)提供服务,包括电子前哨基金会(EFF)、mozilla基金会、akamai(最大的CDN厂商)、cisco等成员创建。大部分操作系统和浏览器默认不安装他的CA根证书,为了克服这个困难,letsencryptCA根证书已经和其他的CA 进行了交叉认证。


Letsencrypt的意义不仅仅是在于免费,更重要的是应用了一种新的、自动化的证书签发机制叫做自动证书管理环境–ACME。常规的证书申请流程都是手动的,通过域名、邮件的交互,其间根据CA的要求进行复杂的审核。Letsencrypt提供了可移植、方便部署的证书管理工具,即使没有人工干预也能快速的申请、签发、部署证书,甚至只需要一个带有几个参数的命令。影响一个产品普及的障碍也许是价格,功能,易用等方面,但就目前低阶的Dv证书而言易用是个人或小团体购买和部署SSL/TLS最大的障碍,而letsencrypt的目标之一就是长期致力于改善和消灭该障碍。

Let’s Encrypt的关键原则是:

  • 免费:任何拥有域名的人都能免费得到一个受信任的证书
  • 自动化:运行在Web服务器上的软件(即官方提供的客户端)能与Let’s Encrypt交互,毫不费力地获取一个证书,安全地配置使用它,自动处理续期
  • 安全:Let’s Encrypt将会作为高级TLS安全最佳实践的一个平台,不论是在证书颁发机构方面还是帮助网络维护者正确地保护他们的服务器方面
  • 透明:所有颁发和撤回的证书都有公开记录,任何人都可以检查
  • 开放:自动颁发和续期协议将会公开为一个开放的标准,其他人也可以采用
  • 合作:就像底层的网络那样,Let’s Encrypt是一次使社区受益的共同努力,不受任何一个组织的控制

 

发展历史

2012年,Mozilla的两个员工发起Let’s Encrypt项目;
2013年5月,ISRG成立;
2013年6月,电子前哨基金会和密歇根大学参与的一个项目合并进来;
2014年11月18日,Let’s Encrypt宣布公开;
2015年1月28日,ACME(Automatic Certificate Management Environment)协议提交到IETF(互联网工程任务小组)请求标准化;
2015年4月9日,ISRG和Linux基金会宣布合作;
2015年6月初,根证书和中间证书生成;
2015年6月16日,宣布最终发布计划:7月27日颁发第一个证书,然后经过一个限量发行期测试安全性和伸缩性,若进展顺利,公共服务预计在9月14日开始提供;
2015年8月7日,推迟发行计划以提供更多时间确保系统安全性和稳定性:9月14日颁发第一个证书,11月16日提供公共服务。与IdenTrust的交叉授权预计会在Let’s Encrypt向公众开放时可用;
2015年9月14日,颁发了第一个证书给域名helloworld.letsencrypt.org
同日,ISRG向Mozilla, Microsoft, Google, Apple提交了根应用申请(英文为root program applications,不确定翻译的对不对);
2015年11月12日,宣布推迟公开服务时间,第一次公测会在12月3日开启;
2015年12月3日,开启公测。

 

申请频率有限制,目前为:

  • 申请限制:每个IP每3小时不超过10次
  • 证书数量限制:每个域名(按二级域名计,子域名的证书也计入二级域名),每7天不超过5个

 

使用

Git clone https://github.com/letsencrypt/letsencrypt

首先确认系统没有安装http服务器软件,比如apache,否则下面的流程可能会不太相同。执行./letsencrypt-auto –help,他将依据当前的发行版自动安装依赖(主要是python的模块)加上-v参数可以看到后台具体在干什么,其中的python-virtualenv目的是要构成letsencrypt的一个运行时环境。一旦完成运行时的建立,将打印帮助信息。以后再执行letsencrypt-auto将直接调用运行时环境中的letsencrypt脚本,比如/root/.local/share/letsencrypt/bin/letsencrypt。注册好域名,确认主机可被访问(家用宽带需要DMZ或端口映射),然后执行/root/.local/share/letsencrypt/bin/letsencrypt certonly -d xxx.com -d 1.xxx.com -d 2.xxx.com
xxx.com可以不用写,因为这种情况下CN会自动包含域),运气好的话会出现以下内容:

IMPORTANT NOTES:

– Congratulations! Your certificate and chain have been saved at

/etc/letsencrypt/live/xxx.com/fullchain.pem. Your cert will

expire on 2016-03-11. To obtain a new version of the certificate in

the future, simply run Let’s Encrypt again.

– If like Let’s Encrypt, please consider supporting our work by:

Donating to ISRG / Let’s Encrypt: https://letsencrypt.org/donate

Donating to EFF: https://eff.org/donate-le

说明证书已经到手,放在/etc/letsencrypt/live/,有效期3个月。对比传统的证书申请方式,可以体会到巨大的便捷。当然运气不好的话可能与域名服务商或域名配置有关,或者是letsencrypt脚本的bugCA 服务器的问题,在成功拿到证书之前也遇到了几次问题,好在log还是能够帮助我解决问题的。

使用如下命令可以查看生成的证书及证书链

openssl x509 -in /etc/letsencrypt/live/xxx.com/cert.pem -noout -text


进阶

前面讲过最简单的申请方式,差不多就一个命令行。如果需要自定一个csr再申请证书就会多出一些步骤。

openssl req -nodes -newkey rsa:2048 -sha256 -outform der -keyout priv.key -out cert.csr -subj ‘/C=US/ST=Texas/L=Houston/O=Hewlett-Packard Company/OU=ISS/CN=xxx.com’ -reqexts SAN -config <(cat /etc/ssl/openssl.cnf <(printf “[SAN]\nsubjectAltName=DNS:1.xxx.com,DNS:2.xxx.com”))

要求生成的csr必须是der格式,而且subjectaltnameSAN)必须存在,否则就会报”授权列表”不存在的错误。

之后可以用以下命令查看csr的文本

openssl req -text -noout -inform der -in cert.csr

如果已有pem格式的csr可以用以下命令转换成der格式

Openssl req -inform pem -in cert.csr -out cert-1.csr -outform der

最后申请签发证书

./letsencrypt-auto –standalone certonly –csr cert.csr

末尾加auth

部署

这里以suse13.2apache2为例

将服务器证书已经信任链证书copy/etc/apache2/ssl.crt/目录

将服务器私钥copy/etc/apache2/ssl.key/目录

Cp /etc/apache2/vhosts.d/vhost-ssl.template /etc/apache2/vhosts.d/vhosts-ssl-1.conf #这将启用ssl的虚拟主机

编辑/etc/apache2/vhosts.d/vhosts-ssl-1.conf,新增/反注释一下内容:

SSLCertificateFile /etc/apache2/ssl.crt/证书.crt

SSLCertificateKeyFile /etc/apache2/ssl.key/私钥.key

SSLCertificateChainFile /etc/apache2/ssl.crt/信任链证书.crt

还没完,会发现并没有监听443,原因是服务器虽然默认启用了ssl的模块(执行a2enmod ssl看到的),但还没有在服务器启用的时候增加ssl参数,可以通过a2enflag SSL启用。

HP GEN8 ILO 证书导入要点

ILO4要求information->overview->iLO HostnameAdministration->security->ssl certificate->common name(CN)完全一致,包括大小写(建议都写小写)

前者在Network中可以设置。

一身冷汗,以为raid挂了

因为最近要再win上面跑seatools看某个SSD的写入量,就把win8装了起来,也跑了跑as ssd。然后重启出现了惊心动魄的一刻,跑到intel raid rom的时候,原来两块500G硬盘组的raid0,显示”incompatible“,顿时冷汗直流,心想这下子完蛋了,早就想把它拆了,结果还是晚了。 初步估计原因是和跑win8里面的as ssd有关。

然后启动了linux,令人惊喜的是isw raid竟然还存在,而且可挂载。还等什么,赶紧把数据备份出来。 然后用dmraid -s -s 看也都是正常,好像只有intel的rom认为这个raid是”incompatible“,google了一下果然发现有人遇到同样的问题,大概是在装完win8之后遇到,而且都是老板子:http://communities.intel.com/message/242967。里面提到刷完新版本的intel rom就会解决该问题,该贴的问题还被作者贴到了win-raid:http://win-raid.com/t459f38-After-Win-install-disks-show-as-quot-Incompatible-quot-in-Intel-RST-BIOS.html最后刷了Intel_MSM_RAID-ROM_v7.5.0.1017.rar后解决了问题。

意外发现找到有现成的rom,正好适用于ASUS P5B-D:http://communities.intel.com/thread/43487,具体链接是http://sdrv.ms/16b2qPJ,是一个onedrive的短链接,需要梯子才能访问。这个rom把ASUS的logo删掉了,因为空间紧张,新版的intel raid rom比较大。刷的时候要用AFUDOS或asus官方的AFU236U。改rom需要用MMTool,工具发布在www.bios-mods.com/downloads。

这里有一份bios modding guides and problems ,写的很全面:http://www.win-raid.com/f16-BIOS-Modding-Guides-and-Problems.html

tsc hpet lapic 内核计时的一些疑惑

事情的缘由是这样的,/sys/device/system/clocksource/clocksource0目录下的available_clocksource和current_clocksource分别显示系统可用的时钟源和当前选择的时钟源。但我并不清楚切换时钟源到底产生什么影响。

available_clocksource的来源自代码sysfs_show_available_clocksources,他实际就是打印挂载clocksource_list链表下面的clocksource结构中的name。对于intel x86一般而言打印的结果包括tsc,hpet,acpi_pm。挂载链表需要通过函数clocksource_register,__clocksource_register_scale对时钟源进行注册。后者实际由包装函数clocksource_register_hz和clocksource_register_khz调用。

那么对于tsc,由init_tsc_clocksource()进行注册。对于hpet由hpet_clocksource_register()注册,acpi_pm由init_acpi_pm_clocksource()注册。此外还有一个clocksource_register()也注册了时钟源i8253,也就是传统的PIT,但却没有在available_clocksource中显示,原因是这个时钟源在符合某些条件下将明确不启用,具体原因看代码init_pit_clocksource。但这并不意味着pit在整个内核中不被使用,实际上内核依旧通过setup_default_timer_irq将pit注册到了irq0,通过cat /proc/interrupt也看得到。可以发现中断数一般不为0,但数字也不大,原因是在注册irq0并启用到hpet注册并启用中间有一段时间,该时间内pit仍然像古董计算机那样作为内核默认(当前)的时钟源。

搞清楚时钟源(clocksource)了再说时钟事件设备(clock_event_device),它的结构中有一个event_handler回调函数,用来触发并驱动内核中已安装的内核定时器。打个比方就像引爆氢弹的那个小原子弹。另外还有一个结构,时钟设备(tick_device),它其实就是clock_event_device的包装结构,多出来的成员mode和clock_event_device.mode中指示的周期触发or单触发模式是基本一致的(深入了解的话启用动态时钟后可能不一致,这里为了简化不考虑动态时钟)。 时钟设备是动态时钟特性引入的结构,这里可以简单认为它就是时钟事件设备。cat /proc/timer_list 可以看到根时钟设备,定时器相关的信息:

该文件分为4个部分,第一部分打印头部,由函数 timer_list_header() 负责:

Timer List Version: v0.7
HRTIMER_MAX_CLOCK_BASES: 4
now at 52813472596941 nsecs

第二部分比较复杂由print_cpu()负责,两层循环打印各个cpu和各个cpu内部4个定时器链中各个定时器的状态

cpu: 1
 clock 0:
  .base:       ffff88017fc8c760
  .index:      0
  .resolution: 1 nsecs
  .get_time:   ktime_get
  .offset:     0 nsecs
active timers:
 #0: , tick_sched_timer, S:01, tick_nohz_idle_exit, swapper/1/0
 # expires at 52813473000000-52813473000000 nsecs [in 403059 to 403059 nsecs]
 #1: , hrtimer_wakeup, S:01, schedule_hrtimeout_range_clock, kwin/1646
 # expires at 52813475032185-52813475082185 nsecs [in 2435244 to 2485244 nsecs]
 #2: , hrtimer_wakeup, S:01, schedule_hrtimeout_range_clock, Chrome_CacheThr/15866
 # expires at 52813613513070-52813619614069 nsecs [in 140916129 to 147017128 nsecs]
 #3: , hrtimer_wakeup, S:01, schedule_hrtimeout_range_clock, chrome/15834
 # expires at 52813774083871-52813774483870 nsecs [in 301486930 to 301886929 nsecs]
 #4: , watchdog_timer_fn, S:01, watchdog_enable, watchdog/1/26
 # expires at 52816686401055-52816686401055 nsecs [in 3213804114 to 3213804114 nsecs]
 #5: , hrtimer_wakeup, S:01, futex_wait_queue_me, chrome/16029
 # expires at 52817513568326-52817513618326 nsecs [in 4040971385 to 4041021385 nsecs]
 #6: , timerfd_tmrproc, S:01, do_timerfd_settime, systemd-journal/414
 # expires at 52820000000000-52820000000000 nsecs [in 6527403059 to 6527403059 nsecs]
 #7: , hrtimer_wakeup, S:01, schedule_hrtimeout_range_clock, kded4/1552
 # expires at 52821469657613-52821478488612 nsecs [in 7997060672 to 8005891671 nsecs]
 #8: , hrtimer_wakeup, S:01, futex_wait_queue_me, BrowserBlocking/15943
 # expires at 52837007486888-52837007536888 nsecs [in 23534889947 to 23534939947 nsecs]
 #9: , timerfd_tmrproc, S:01, do_timerfd_settime, systemd/1
 # expires at 52840250000000-52840250000000 nsecs [in 26777403059 to 26777403059 nsecs]
 #10: , hrtimer_wakeup, S:01, futex_wait_queue_me, chrome/16827
 # expires at 52850026037451-52850026087451 nsecs [in 36553440510 to 36553490510 nsecs]
 #11: , hrtimer_wakeup, S:01, schedule_hrtimeout_range_clock, master/1116
 # expires at 52851644484709-52851704484708 nsecs [in 38171887768 to 38231887767 nsecs]
 #12: , hrtimer_wakeup, S:01, futex_wait_queue_me, WorkerPool/147/9520
 # expires at 52987931753150-52987931803150 nsecs [in 174459156209 to 174459206209 nsecs]
 #13: , hrtimer_wakeup, S:01, futex_wait_queue_me, WorkerPool/149/9546
 # expires at 52987932822056-52987932872056 nsecs [in 174460225115 to 174460275115 nsecs]
 #14: , hrtimer_wakeup, S:01, futex_wait_queue_me, WorkerPool/48/12843
 # expires at 53002566669134-53002566719134 nsecs [in 189094072193 to 189094122193 nsecs]
 #15: , hrtimer_wakeup, S:01, futex_wait_queue_me, WorkerPool/97/6284
 # expires at 53003147109047-53003147159047 nsecs [in 189674512106 to 189674562106 nsecs]
 #16: , hrtimer_wakeup, S:01, schedule_hrtimeout_range_clock, qmgr/1118
 # expires at 53091644442566-53091744442566 nsecs [in 278171845625 to 278271845625 nsecs]
 #17: , hrtimer_wakeup, S:01, schedule_hrtimeout_range_clock, NetworkManager/876
 # expires at 53109000969906-53109100969906 nsecs [in 295528372965 to 295628372965 nsecs]
 #18: , it_real_fn, S:01, do_setitimer, qmgr/1118
 # expires at 53124644427060-53124644427060 nsecs [in 311171830119 to 311171830119 nsecs]
 #19: , it_real_fn, S:01, do_setitimer, master/1116
 # expires at 53124644484430-53124644484430 nsecs [in 311171887489 to 311171887489 nsecs]
 #20: , hrtimer_wakeup, S:01, futex_wait_queue_me, WorkerPool/44/13426
 # expires at 53188257243107-53188257293107 nsecs [in 374784646166 to 374784696166 nsecs]
 #21: , hrtimer_wakeup, S:01, futex_wait_queue_me, WorkerPool/41/9679
 # expires at 53189846117399-53189846167399 nsecs [in 376373520458 to 376373570458 nsecs]
 #22: , hrtimer_wakeup, S:01, futex_wait_queue_me, WorkerPool/249/13559
 # expires at 53287021792511-53287021842511 nsecs [in 473549195570 to 473549245570 nsecs]
 #23: , hrtimer_wakeup, S:01, futex_wait_queue_me, WorkerPool/1175/11753
 # expires at 53404805411154-53404805461154 nsecs [in 591332814213 to 591332864213 nsecs]
 #24: , hrtimer_wakeup, S:01, futex_wait_queue_me, WorkerPool/1524/15244
 # expires at 53404827318575-53404827368575 nsecs [in 591354721634 to 591354771634 nsecs]
 #25: , hrtimer_wakeup, S:01, schedule_hrtimeout_range_clock, Chrome_FileThre/15863
 # expires at 53586342492462-53586442492462 nsecs [in 772869895521 to 772969895521 nsecs]
 #26: , hrtimer_wakeup, S:01, schedule_hrtimeout_range_clock, dhclient/11767
 # expires at 87553216902146-87553316902146 nsecs [in 34739744305205 to 34739844305205 nsecs]
 #27: , hrtimer_wakeup, S:01, futex_wait_queue_me, Chrome_DBThread/15862
 # expires at 89583413156055-89583413206055 nsecs [in 36769940559114 to 36769940609114 nsecs]
 clock 1:
  .base:       ffff88017fc8c7a0
  .index:      1
  .resolution: 1 nsecs
  .get_time:   ktime_get_real
  .offset:     1445646478326986436 nsecs
active timers:
 #0: , hrtimer_wakeup, S:01, futex_wait_queue_me, QThread/1942
 # expires at 1445699294416776000-1445699294416826000 nsecs [in 1445646480944179059 to 1445646480944229059 nsecs]
 #1: , timerfd_tmrproc, S:01, do_timerfd_settime, systemd/1425
 # expires at 9223372036854775807-9223372036854775807 nsecs [in 9223319223382178866 to 9223319223382178866 nsecs]
 clock 2:
  .base:       ffff88017fc8c7e0
  .index:      2
  .resolution: 1 nsecs
  .get_time:   ktime_get_boottime
  .offset:     29936432888514 nsecs
active timers:
 clock 3:
  .base:       ffff88017fc8c820
  .index:      3
  .resolution: 1 nsecs
  .get_time:   ktime_get_clocktai
  .offset:     1445646478326986436 nsecs
active timers:
  .expires_next   : 52813474000000 nsecs
  .hres_active    : 1
  .nr_events      : 13118249
  .nr_retries     : 1557
  .nr_hangs       : 0
  .max_hang_time  : 0 nsecs
  .nohz_mode      : 2
  .last_tick      : 52813467000000 nsecs
  .tick_stopped   : 0
  .idle_jiffies   : 4347480763
  .idle_calls     : 127885
  .idle_sleeps    : 122866
  .idle_entrytime : 52813471757310 nsecs
  .idle_waketime  : 52813455529583 nsecs
  .idle_exittime  : 52813471757310 nsecs
  .idle_sleeptime : 585808925443 nsecs
  .iowait_sleeptime: 8495380650 nsecs
  .last_jiffies   : 4347480763
  .next_jiffies   : 4347480795
  .idle_expires   : 52813498000000 nsecs
jiffies: 4347480770
......

第三部分是打印负责广播事件的tickdevice信息,由timer_list_show_tickdevice_header()负责:

Tick Device: mode:     1
Broadcast device
Clock Event Device: hpet
 max_delta_ns:   149983013276
 min_delta_ns:   13410
 mult:           61496111
 shift:          32
 mode:           4
 next_event:     9223372036854775807 nsecs
 set_next_event: hpet_legacy_next_event
 set_mode:       hpet_legacy_set_mode
 event_handler:  tick_handle_oneshot_broadcast
 retries:        0

tick_broadcast_mask: 00000000
tick_broadcast_oneshot_mask: 00000000

第四部分是打印各个cpu上的tickdevice,由print_tickdevice()负责:

Tick Device: mode:     1
Per CPU device: 0
Clock Event Device: lapic
 max_delta_ns:   103080567906
 min_delta_ns:   1000
 mult:           89477311
 shift:          32
 mode:           3
 next_event:     52813475000000 nsecs
 set_next_event: lapic_next_event
 set_mode:       lapic_timer_setup
 event_handler:  hrtimer_interrupt
 retries:        4

Tick Device: mode:     1
Per CPU device: 1
Clock Event Device: lapic
 max_delta_ns:   103080567906
 min_delta_ns:   1000
 mult:           89477311
 shift:          32
 mode:           3
 next_event:     52813474000000 nsecs
 set_next_event: lapic_next_event
 set_mode:       lapic_timer_setup
 event_handler:  hrtimer_interrupt
 retries:        0

Tick Device: mode:     1
Broadcast device
Clock Event Device: hpet
 max_delta_ns:   149983013276
 min_delta_ns:   13410
 mult:           61496111
 shift:          32
 mode:           1
 next_event:     9223372036854775807 nsecs
 set_next_event: hpet_legacy_next_event
 set_mode:       hpet_legacy_set_mode
 event_handler:  tick_handle_oneshot_broadcast
 retries:        0

tick_broadcast_mask: 00000000
tick_broadcast_oneshot_mask: 00000000

Tick Device: mode:     1
Per CPU device: 0
Clock Event Device: lapic
 max_delta_ns:   103080567906
 min_delta_ns:   1000
 mult:           89477311
 shift:          32
 mode:           3
 next_event:     40610606442603 nsecs
 set_next_event: lapic_next_event
 set_mode:       lapic_timer_setup
 event_handler:  hrtimer_interrupt
 retries:        1

Tick Device: mode:     1
Per CPU device: 1
Clock Event Device: lapic
 max_delta_ns:   103080567906
 min_delta_ns:   1000
 mult:           89477311
 shift:          32
 mode:           3
 next_event:     40610612271380 nsecs
 set_next_event: lapic_next_event
 set_mode:       lapic_timer_setup
 event_handler:  hrtimer_interrupt
 retries:        0

看到这里感觉有点奇怪啊,tsc和acpi_pm怎么没有啊?难道这种时钟源没有包装成时钟事件设备?回到代码找证据,先看clock_event_device的注册,由两个函数,clockevents_register_device和clockevent_config_and_register,后面一个实际上包裹了前一个。setup_APIC_timer注册了lapic。init_one_hpet_msi_clockevent依据cpu插入事件注册了hpet。clockevent_i8253_init注册了pit,当然如果启用了hpet,则不会走这个代码,他们是互斥的。然后就没有了,确认了,tsc和acpi_pm不会被注册成时钟事件设备,那么会不会直接注册成时钟设备呢?继续看代码,注册时钟设备是通过tick_setup_device实现,该函数主要会在时钟事件设备注册时由clockevents_notify_release调用。所以他们肯定只能作为时钟源来使用了。另一个值的注意的是hpet既可以作为时钟源也可以作为时钟设备,lapic只能作为时钟设备。

为什么,通过浏览tsc的代码我发现它不能用来计时,简单来说它不能通过中断来产生“滴答”,而只能通过read_tsc来读一个时间戳,而这也就是时钟源的含义。那么时钟源怎么用的?可以使用clock_gettime系统调用来观察。

clock_gettime -> sys_call -> sys_clock_gettime -> getnstimeofday -> timekeeping_get_ns->read_tsc -> native_read_tsc

红色的部分就是clocksource的read虚函数。切换current_clocksource也就是切换这个虚函数的实现。

了解libtool

之前对这个东西一知半解,最近在porting几个库的时候感觉还是了解一下比较好。

libtool与动态链接库有很大关系,初衷是为了解决库依赖的问题,打个比方a.so依赖b.so,那么编译的时候要在-l参数后面把这些so都加上去。libtool的概念是不使用-l,而是指定描述依赖关系的文件进而自动生成编译参数。有点像apt,zypper,yum等工具的原理。

libtool是一个脚本文件,如果要使用,既可以直接安装,也可以使用软件包中的configure生成。然而在实际使用中由configure生成的libtool脚本优先级高于系统安装的,或者根本就不用系统安装的,所以不单独安装libtool也没有问题。

为了说明简单,这里抛弃configure工具,直接安装并使用libtool进行示范。

先随便写一个foo.c里面就一个函数,然后使用libtool编译成动态库而不是gcc

1.先编译出目标文件:

libtool --mode=compile --tag=CC mipsel-linux-gcc -c foo.c

输出

libtool: compile:  mipsel-linux-gcc -c foo.c  -fPIC -DPIC -o .libs/foo.o
libtool: compile:  mipsel-linux-gcc -c foo.c -o foo.o >/dev/null 2>&1

第一行生成一个位置无关的obj,第二行生成一个位置相关的obj,两个分别为接下来的动态库和静态库准备。

可以看出libtool实际上封装了gcc,除了gcc的work外他还做了一些其他工作,另外输出的文件和目录都是有规范的。

–tag=CC在交叉编译的时候必须指定。

最重要的是它生成了.lo文件,该文件描述了前述两个obj文件的路径。

# foo.lo - a libtool object file
# Generated by ltmain.sh (GNU libtool) 2.2.6
#
# Please DO NOT delete this file!
# It is necessary for linking the library.

# Name of the PIC object.
pic_object='.libs/foo.o'

# Name of the non-PIC object
non_pic_object='foo.o'


2.生成库:

./libtool --mode=link --tag=CC mipsel-linux-gcc -o foo.la foo.lo -rpath /tmp

输出

libtool: link: mipsel-linux-gcc -shared  .libs/foo.o      -Wl,-soname -Wl,libfoo.so.0 -o .libs/libfoo.so.0.0.0
libtool: link: (cd ".libs" && rm -f "libfoo.so.0" && ln -s "libfoo.so.0.0.0" "libfoo.so.0")
libtool: link: (cd ".libs" && rm -f "libfoo.so" && ln -s "libfoo.so.0.0.0" "libfoo.so")
libtool: link: mipsel-linux-ar cru .libs/libfoo.a  foo.o
libtool: link: mipsel-linux-ranlib .libs/libfoo.a
libtool: link: ( cd ".libs" && rm -f "libfoo.la" && ln -s "../libfoo.la" "libfoo.la" )

-rpath参数必须指定否则无法生成动态库,该参数在gcc中意思是runtime时库的搜索路径,这里也同时告诉libtool该库要安装到哪个目录。obj不再是输入文件而是改为了.lo。最后生成了动态库,静态库还有.la文件。该文件描述了动态库的依赖,所以libtool折腾了半天为了就是这个:

# libfoo.la - a libtool library file
# Generated by ltmain.sh (GNU libtool) 2.2.6
#
# Please DO NOT delete this file!
# It is necessary for linking the library.

# The name that we can dlopen(3).
dlname='libfoo.so.0'

# Names of this library.
library_names='libfoo.so.0.0.0 libfoo.so.0 libfoo.so'

# The name of the static archive.
old_library='libfoo.a'

# Linker flags that can not go in dependency_libs.
inherited_linker_flags=''

# Libraries that this one depends upon.
dependency_libs=''

# Names of additional weak libraries provided by this library
weak_library_names=''

# Version information for libdaemon.
current=0
age=0
revision=0

# Is this an already installed library?
installed=no

# Should we warn about portability when linking against -modules?
shouldnotlink=no

# Files to dlopen/dlpreopen
dlopen=''
dlpreopen=''

# Directory that this library needs to be installed in:
libdir='/tmp'

libdir指出了库的安装位置;library_names记录了动态库的名字;old_library记录了静态库的名字。

如果在链接过程中加入-l参数,也就是有依赖库,那么生成的.la中的dependency_libs中就会加入这个库。可以想象对于一个比较复杂的项目,透过.la可以形成一个完整的依赖链。libtool再处理-l参数时,比如-lz,并不是找libz.so,而是libz.la,一切都明了了。

这里有个需要注意的地方,因为libtool一般是makefile调用,所以当使用别人编译出来的so,la文件时,libdir指定的目录往往和自己的环境不一样,导致makefile报错,如果不知道这个错误实际上是由libtool引发的话你会很郁闷,因为即使so就放在那里但其实还是按照la指定的去找。解决方法是修改la文件,更dirty的方法是删除la文件,让gcc按照链接器搜索的顺序去找so(见下文的具体解释)

3.安装

./libtool --mode=install install -c libfoo.la /tmp/

这里要再一次指定相同的tmp目录,尽管链接的时候指明了。

输出:

libtool: install: install -c .libs/libfoo.so.0.0.0 /tmp/libfoo.so.0.0.0
libtool: install: (cd /tmp && { ln -s -f libfoo.so.0.0.0 libfoo.so.0 || { rm -f libfoo.so.0 && ln -s libfoo.so.0.0.0 libfoo.so.0; }; })
libtool: install: (cd /tmp && { ln -s -f libfoo.so.0.0.0 libfoo.so || { rm -f libfoo.so && ln -s libfoo.so.0.0.0 libfoo.so; }; })
libtool: install: install -c .libs/libfoo.lai /tmp/libfoo.la
libtool: install: install -c .libs/libfoo.a /tmp/libfoo.a
libtool: install: chmod 644 /tmp/libfoo.a
libtool: install: mipsel-linux-ranlib /tmp/libfoo.a
libtool: finish: PATH="/run/media/root/RAID_STO-4_645G/DEV/PORTING/baffalo-HP54-G/TOOLCHAIN/OpenWrt-SDK-Linux-x86_64-1/bin/:/sbin:/usr/local/sbin:/root/bin:/usr/local/bin:/usr/bin:/bin:/usr/bin/X11:/usr/games:/sbin" ldconfig -n /tmp
ldconfig: /tmp/libfoo.so.0.0.0 is for unknown machine 8.

ldconfig: /tmp/libfoo.so is for unknown machine 8.

ldconfig: /tmp/libfoo.so.0 is for unknown machine 8.

----------------------------------------------------------------------
Libraries have been installed in:
   /tmp

If you ever happen to want to link against installed libraries
in a given directory, LIBDIR, you must either use libtool, and
specify the full pathname of the library, or use the `-LLIBDIR'
flag during linking and do at least one of the following:
   - add LIBDIR to the `LD_LIBRARY_PATH' environment variable
     during execution
   - add LIBDIR to the `LD_RUN_PATH' environment variable
     during linking
   - use the `-Wl,-rpath -Wl,LIBDIR' linker flag
   - have your system administrator add LIBDIR to `/etc/ld.so.conf'

See any operating system documentation about shared libraries for
more information, such as the ld(1) and ld.so(8) manual pages.
----------------------------------------------------------------------

4.卸载

libtool --mode=uninstall rm /tmp/libfoo.la

输出

libtool: uninstall: rm /tmp/libfoo.la /tmp/libfoo.so.0.5.0 /tmp/libfoo.so.0 /tmp/libfoo.so /tmp/libfoo.a

5.使用库
假设有个main.c作为程序入口,需要libfoo.so,则libtool的用法是:

libtool --mode=compile gcc -c main.c
libtool --mode=link gcc -o main main.lo /tmp/libfoo.la

可以想象如果是一个非常复杂的项目,借助libtool可以将编译参数变得像编译helloworld一样简洁

-L: “链接”的时候,去找的目录,也就是所有的 -lFOO 选项里的库,都会先从 -L 指定的目录去找,然后是默认的地方。
-rpath: “运行”的时候,去找的目录。运行的时候,要找 .so 文件,会从这个选项里指定的地方去找。对于交叉编译,只有配合 –sysroot 选项才能起作用。
-rpath_link (或者 -rpath-link):这个也是用于“链接”的时候的,例如你显示指定的需要 FOO.so,但是 FOO.so 本身是需要 BAR.so 的,后者你并没有指定,而是 FOO.so 引用到它,这个时候,会先从 -rpath-link 给的路径里找。

也就是说,-rpath指定的路径会被记录在生成的可执行程序中,用于运行时。
-rpath-link 则只用于链接时。

这里再引出一个问题,如果libtool的依赖链断了怎么办?也就是某个依赖的动态库不是libtool生成的,没有那个关键的.la文件。

libtool确实不会处理这种情况了,但他会交给链接器处理,链接器依据以下顺序去搜索动态库so文件:

1. 所有由’-rpath-link’选项指定的搜索路径。
2. 所有由’-rpath’指定的搜索路径。’-rpath’跟’-rpath_link’的不同之处在于,由’-rpath’指定的路径被包含在可执行文件中,并在运行时使用,而’-rpath-link’选项仅仅在连接时起作用。
3. 在一个ELF系统中, 如果’-rpath’和’rpath-link’选项没有被使用。
会搜索环境变量’LD_RUN_PATH’的内容.它也只对本地连接器起作用。
4. 在SunOS上, ‘-rpath’选项不使用, 只搜索所有由’-L’指定的目录。
5. 对于一个本地连接器,环境变量’LD_LIBRARY_PATH’的内容被搜索。
6.对于一个本地ELF连接器,共享库中的`DT_RUNPATH’和`DT_RPATH’操作符会被需要它的共享库搜索。
如果’DT_RUNPATH’存在了, 那’DT_RPATH’就会被忽略。
7. 缺省目录, 常规的,如’/lib’和’/usr/lib’。
8. 对于ELF系统上的本地链接器, 如果文件’/etc/ld.so.conf’存在,这个文件中有的目录会被搜索.
从以上可以看出,在使用本地工具链进行本地编译情况下,只要库存在于某个位置,gcc总能通过如上策略找到需要的共享库。但在交叉编译下,上述八种策略,可以使用的仅仅有两个:-rpath-link,-rpath。这两个选项在上述八种策略当中优先级最高,当指定这两个选项时,如果链接需要的共享库找不到,链接器会优先到这两个选项指定的路径下去搜索需要的共享库。通过上面的描述可以看到:-rpath指定的路径将被写到可执行文件中;-rpath-link则不会;我们当然不希望交叉编译情况下使用的路径信息被写进最终的可执行文件,所以我们选择使用选项-rpath-link。

libtool和pkg-config的关系:

这两个东西都很常见,libtool已经了解了,那pkg-config和它是什么关系?

如果configure确实使用了pkg-config的话也就是获得libtool所需要的-I -L -l参数而已,然后传给libtool,所以他们之间不直接打交道。

最后,libtool不能处理头文件,也就是说你用libtool安装了so却没有安装头文件,所以还要手动cp头文件到相应目录。

对于多数库项目还提供pkg-config信息。有些项目只生成可执行文件,自身不再作为动态库为别的共享,那么往往在Makefile见不到libtool,而只是利用pkg-config生成编译参数,直接用gcc完成编译。