Skip to content

Latest commit

 

History

History
323 lines (294 loc) · 12.6 KB

cisco-self-signed-certificates-field-notice-70489.md

File metadata and controls

323 lines (294 loc) · 12.6 KB

Cisco Field Notice: FN - 70489 - PKI Self-Signed Certificate Expiration in Cisco IOS and Cisco IOS XE Software

Name: Cisco FN#70489 - IOS-PKI Self-Signed Certificate Expiration

Intent: Find Cisco device affected by the Field Notice 70489

Description: This check finds all Cisco device running IOS and Cisco IOS XE software affected by the Field Notice 70489
Problem description:
Self-signed X.509 PKI certificates (SSC) that were generated on devices that run affected Cisco IOS or Cisco IOS XE software releases expire on 2020-01-01 00:00:00 UTC. New self-signed certificates cannot be created on affected devices after 2020-01-01 00:00:00 UTC. Any service that relies on these self-signed certificates to establish or terminate a secure connection might not work after the certificate expires.

Check the Field Notice for workarounds and solutions.

Query:

// Versions that are affected. Note that these version strings are actually patterns
// with * indicating any number of arbitrary characters. For example, the first version pattern is "12.x" which matches
// versions like 12.1, 12.231, and so on.
affectedVersions =
  ["12.*",
   "15.0.*",
   "15.1.*",
   "15.2.*",
   "15.3.*",
   "15.4.*",
   "15.5.*",
   "15.6(1)S",
   "15.6(1)S1",
   "15.6(1)S2",
   "15.6(1)S3",
   "15.6(1)S4",
   "15.6(1)SN",
   "15.6(1)SN1",
   "15.6(1)T",
   "15.6(1)T0a",
   "15.6(1)T1",
   "15.6(1)T2",
   "15.6(1)T3",
   "15.6(2)S",
   "15.6(2)S1",
   "15.6(2)S2",
   "15.6(2)S3",
   "15.6(2)S4",
   "15.6(2)SP",
   "15.6(2)SP1",
   "15.6(2)SP2",
   "15.6(2)SP3",
   "15.6(2)SP4",
   "15.6(2)SP6",
   "15.6(2)T",
   "15.6(2)T0a",
   "15.6(2)T1",
   "15.6(2)T2",
   "15.6(2)T3",
   "15.6(3)M",
   "15.6(3)M0a",
   "15.6(3)M1",
   "15.6(3)M1a",
   "15.6(3)M1b",
   "15.6(3)M2",
   "15.6(3)M2a",
   "15.6(3)M3",
   "15.6(3)M3a",
   "15.6(3)M4",
   "15.6(3)M5",
   "15.6(3)M6",
   "15.6(3)M6a",
   "15.7(3)M",
   "15.7(3)M1",
   "15.7(3)M2",
   "15.7(3)M3",
   "15.7(3)M4",
   "15.7(3)M4a",
   "15.7(3)M4b",
   "15.8(3)M",
   "15.8(3)M0a",
   "15.8(3)M0b",
   "15.8(3)M1",
   "15.8(3)M1a",
   "15.8(3)M2",
   "15.8(3)M2a",
   "15.9(3)M0a",
   "16.1.0",
   "16.1.1",
   "16.1.2",
   "16.1.3",
   "16.2.1",
   "16.2.2",
   "16.3.1",
   "16.3.1a",
   "16.3.2",
   "16.3.3",
   "16.3.4",
   "16.3.5",
   "16.3.5b",
   "16.3.6",
   "16.3.7",
   "16.3.8",
   "16.3.9",
   "16.4.1",
   "16.4.2",
   "16.4.3",
   "16.5.1",
   "16.5.1a",
   "16.5.1b",
   "16.5.2",
   "16.5.3",
   "16.6.1",
   "16.6.1a",
   "16.6.2",
   "16.6.3",
   "16.6.4",
   "16.6.4a",
   "16.6.5",
   "16.6.5a",
   "16.6.6",
   "16.6.7",
   "16.7.1",
   "16.7.1a",
   "16.7.1b",
   "16.7.2",
   "16.7.3",
   "16.7.4",
   "16.8.1",
   "16.8.1a",
   "16.8.1b",
   "16.8.1c",
   "16.8.1d",
   "16.8.1e",
   "16.8.2",
   "16.8.3"
  ];

// Determines if the given device may be affected by the field notice, based on two criteria:
//  (1) the device OS is either IOS or IOS-XE, and
//  (2) the OS version matches at least one of the affected version strings listed above.
isAffectedPlatform(device) =
  (device.platform.os == OS.IOS || device.platform.os == OS.IOS_XE) &&
  (!isPresent(device.platform.osVersion) || length((foreach versionPattern in affectedVersions
                                                    where matches(device.platform.osVersion, versionPattern)
                                                    select versionPattern)) > 0);

// For the given device, get the trustpoints that have "enrollment selfsigned" set defined for the given device.
// Includes the number of self-signed certs declared for the trustpoint.
getTrustPointsWithSelfSignedCerts(device) =
  foreach line in device.files.config
  let crypto = patternMatch(line.text, `crypto pki trustpoint {tpName:string}`)
  where isPresent(crypto)
  let enrollmentLines = (foreach cryptoLine in line.children
                         where isPresent(patternMatch(cryptoLine.text, `enrollment selfsigned`))
                         select cryptoLine.text)
  where length(enrollmentLines) > 0
  let certLines = (foreach line in device.files.config
                   let cryptoCertChain = patternMatch(line.text, `crypto pki certificate chain {tpName:string}`)
                   where isPresent(cryptoCertChain) && cryptoCertChain.tpName == crypto.tpName
                   foreach certLine in line.children
                   where isPresent(patternMatch(certLine.text, `certificate self-signed`))
                   select certLine.text)
  select { tpName: crypto.tpName,
           numSelfSignedCerts: length(certLines)
         };

// True if this line is "ip http secure-server".
usedInHttpSecureServer(line) =
  isPresent(patternMatch(line.text, `ip http secure-server`));

// True if this line applies the trustpoint in a "ip http secure-trustpoint" command.
usedInHttpSecureTrustpoint(line, tpName) =
  length((foreach match in [patternMatch(line.text, `ip http secure-trustpoint {tpName:string}`)]
          where isPresent(match) && match.tpName == tpName
          select line)) > 0;

// True if this line applies the trustpoint in "crypto signaling default" or "crypto signaling remote-addr" commands.
usedInSipOverTls(line, tpName) =
  length((foreach match in [patternMatch(line.text, `crypto signaling default trustpoint {tpName:string}`),
                            patternMatch(line.text, `crypto signaling remote-addr {ipv4Address} {ipv4Address} trustpoint {tpName:string}`)
                           ]
          where isPresent(match) && match.tpName == tpName
          select line)) > 0;

// True if this line applies the trustpoint in "secure-signaling" or "tftp-server-credentials" commands underneath
// the "telephony-service" configuration section.
usedInTelephonyService(line, tpName) =
  isPresent(patternMatch(line.text, `telephony-service`)) &&
  length((foreach child in line.children
          let match1 = patternMatch(child.text, `secure-signaling trustpoint {tpName:string}`)
          let match2 = patternMatch(child.text, `tftp-server-credentials trustpoint {tpName:string}`)
          where (isPresent(match1) && match1.tpName == tpName) ||
                (isPresent(match2) && match2.tpName == tpName)
          select child.text)) > 0;

// True if this line applies the trustpoint under "credentials" configuration section.
usedInCredentials(line, tpName) =
  isPresent(patternMatch(line.text, `credentials`)) &&
  length((foreach child in line.children
          let match = patternMatch(child.text, `trustpoint {tpName:string}`)
          where isPresent(match) && match.tpName == tpName
          select child.text)) > 0;

// True if this line applies the trustpoint under various "dpsfarm" configurations.
usedInDspFarm(line, tpName) =
  isPresent(patternMatch(line.text, `dspfarm profile {number} {"conference" | "mtp" | "transcode"} security`)) &&
  length((foreach match in [patternMatch(line.text, `trustpoint {tpName:string}`)]
          where isPresent(match) && match.tpName == tpName
          select match)) > 0;

// True if this line applies the trustpoint in a "stcapp security" command.
usedInStcApp(line, tpName) =
  length((foreach match in [patternMatch(line.text, `stcapp security trustpoint {tpName:string}`)]
          where isPresent(match) && match.tpName == tpName
          select match)) > 0;

// True if this line applies the trustpoint under a "webvpn gateway" configuration.
usedInWebVpn(line, tpName) =
  isPresent(patternMatch(line.text, `webvpn gateway {string}`)) &&
  length((foreach match in [patternMatch(line.text, `ssl trustpoint {tpName:string}`)]
          where isPresent(match) && match.tpName == tpName
          select match)) > 0;

// True if this line applies the trustpoint under a "crypto ssl policy" configuration.
usedInSslVpn(line, tpName) =
  isPresent(patternMatch(line.text, `crypto ssl policy {string}`)) &&
  length((foreach match in [patternMatch(line.text, `pki trustpoint {tpName:string} sign`)]
          where isPresent(match) && match.tpName == tpName
          select match)) > 0;

// True if this line applies the trustpoint under a IKEv2 configuration.
usedInIkeV2(line, tpName) =
  isPresent(patternMatch(line.text, `crypto ikev2 profile {string}`)) &&
  length((foreach subline in line.children
          where isPresent(patternMatch(subline.text, `authentication local rsa-sig`))
          select line.text)) > 0 &&
  length((foreach subline in line.children
          let match = patternMatch(subline.text, `pki trustpoint {tpName:string}`)
          where isPresent(match) && match.tpName == tpName
          select line.text)) > 0;

// True if this line applies the trustpoint under a ISAKMP profile configuration.
usedInIsaKmpProfile(line, tpName) =
  isPresent(patternMatch(line.text, `crypto isakmp profile {string}`)) &&
  length((foreach subline in line.children
          let match = patternMatch(subline.text, `ca trustpoint {tpName:string}`)
          where isPresent(match) && match.tpName == tpName
          select line.text)) > 0;

// True if this line applies the trustpoint under a ISAKMP policy configuration.
usedInIsaKmpPolicy(line, tpName) =
  isPresent(patternMatch(line.text, `crypto isakmp policy {number}`)) &&
  length((foreach subline in line.children
          let match = patternMatch(subline.text, `authentication {method:string}`)
          where isPresent(match) && match.method not in ["pre-share", "rsa-encr"]
          select line.text)) > 0;

// True if this line applies the trustpoint under a ISAKMP configuration.
usedInIsaKmp(line, tpName) =
  usedInIsaKmpProfile(line, tpName) || usedInIsaKmpPolicy(line, tpName);

// True if this line applies the trustpoint under an "ip ssh server" configuration.
usedInSshServer(line, tpName) =
  isPresent(patternMatch(line.text, `ip ssh server certificate profile`)) &&
  length((foreach subline in line.children
          where isPresent(patternMatch(subline.text, `server`))
          foreach subsubline in subline.children
          let match = patternMatch(subsubline.text, `trustpoint sign {tpName:string}`)
          where isPresent(match) && match.tpName == tpName
          select line.text)) > 0;

// True if this line applies the trustpoint under an "restconf" configuration.
usedInRestConf(line, tpName) =
  isPresent(patternMatch(line.text, `restconf`)) &&
  length((foreach subline in line.children
          // In the following, the client keyword is optional. In other words, the pattern below matches both
          // ip http client secure-trustpoint abc and ip http secure-trustpoint abc commands.
          let match = patternMatch(subline.text, `ip http {"client" | empty} secure-trustpoint {tpName:string}`)
          where isPresent(match) && match.tpName == tpName
          select line.text)) > 0;


// Returns the collection of config lines that apply the given trustpoint to some feature (on the given device).
trustpointFeatures(device, tpName) =
  foreach line in device.files.config
  where usedInHttpSecureServer(line) ||
        usedInHttpSecureTrustpoint(line, tpName) ||
        usedInSipOverTls(line, tpName) ||
        usedInTelephonyService(line, tpName) ||
        usedInCredentials(line, tpName) ||
        usedInDspFarm(line, tpName) ||
        usedInStcApp(line, tpName) ||
        usedInWebVpn(line, tpName) ||
        usedInSslVpn(line, tpName) ||
        usedInSshServer(line, tpName) ||
        usedInRestConf(line, tpName) ||
        usedInIkeV2(line, tpName) ||
        usedInIsaKmp(line, tpName)
  select line.text;


// The overall query.
// The query finds all devices that are affected by the field notice.
// It then finds all trustpoints that have self-signed certificates, and finds those that were applied to
// one or more features.
foreach device in network.devices
where isAffectedPlatform(device)
foreach tp in getTrustPointsWithSelfSignedCerts(device)
let features = trustpointFeatures(device, tp.tpName)
where length(features) > 0
select { Confidence: if tp.numSelfSignedCerts > 0 then "High" else "Medium",
         Device: device.name,
         OS: device.platform.os,
         Version: device.platform.osVersion,
         TrustPointName: tp.tpName,
         Features: features
       }

Query result example: Cisco Field Notice 70489

Notes: By default Forward Enterprise filters out sensitive data (e.g., password fields, SNMP server names) from the device configuration. The check provides a Confidence level based on the data collected. To get more accurate check results, you need to disable the data filtering in the Collector configuration Advanced settings.

Disable Data Filtering