Skip to content

Commit a3ae98f

Browse files
committed
fix(analyzer): detect OpenSSL 3.x in OpenSSLAnalyzer
OpenSSL 3.x defines OPENSSL_VERSION_NUMBER as a macro expression rather than a literal hex constant, so the existing regex never matches and the analyzer drops the dependency. As a result, 3.x source trees produce no CPE and never match NVD CVEs. Add a second pattern that captures OPENSSL_VERSION_STR "X.Y.Z" (introduced in 3.0); fall back to the legacy NUMBER pattern for 1.x and earlier. Adds a test fixture/case using opensslv.h from OpenSSL 3.5.6.
1 parent 18af98b commit a3ae98f

3 files changed

Lines changed: 172 additions & 18 deletions

File tree

core/src/main/java/org/owasp/dependencycheck/analyzer/OpenSSLAnalyzer.java

Lines changed: 30 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,20 @@ public class OpenSSLAnalyzer extends AbstractFileTypeAnalyzer {
6868
*/
6969
private static final FileFilter OPENSSLV_FILTER = FileFilterBuilder.newInstance().addFilenames(OPENSSLV_H).build();
7070
/**
71-
* Open SSL Version number pattern.
71+
* Open SSL Version number pattern (OpenSSL 1.x and earlier — literal hex constant).
7272
*/
7373
private static final Pattern VERSION_PATTERN = Pattern.compile(
7474
"define\\s+OPENSSL_VERSION_NUMBER\\s+0x([0-9a-zA-Z]{8})L", Pattern.DOTALL
7575
| Pattern.CASE_INSENSITIVE);
76+
/**
77+
* Open SSL version string pattern (OpenSSL 3.x — {@code OPENSSL_VERSION_STR "X.Y.Z"}).
78+
* In 3.x, {@code OPENSSL_VERSION_NUMBER} is a macro expression that the
79+
* legacy {@link #VERSION_PATTERN} cannot match, so this is the authoritative
80+
* source of the version on 3.x headers.
81+
*/
82+
private static final Pattern VERSION_STR_PATTERN = Pattern.compile(
83+
"define\\s+OPENSSL_VERSION_STR\\s+\"([^\"]+)\"", Pattern.DOTALL
84+
| Pattern.CASE_INSENSITIVE);
7685
/**
7786
* The offset of the major version number.
7887
*/
@@ -191,28 +200,31 @@ protected void analyzeDependency(Dependency dependency, Engine engine)
191200
throws AnalysisException {
192201
final File file = dependency.getActualFile();
193202
final String parentName = file.getParentFile().getName();
194-
boolean found = false;
195203
final String contents = getFileContents(file);
204+
String version = null;
196205
if (!contents.isEmpty()) {
197-
final Matcher matcher = VERSION_PATTERN.matcher(contents);
198-
if (matcher.find()) {
199-
found = true;
200-
final String version = getOpenSSLVersion(Long.parseLong(matcher.group(1), HEXADECIMAL));
201-
dependency.addEvidence(EvidenceType.VERSION, OPENSSLV_H, "Version Constant",
202-
version, Confidence.HIGH);
203-
try {
204-
final PackageURL purl = PackageURLBuilder.aPackageURL().withType("generic")
205-
.withName("openssl").withVersion(version).build();
206-
dependency.addSoftwareIdentifier(new PurlIdentifier(purl, Confidence.HIGHEST));
207-
} catch (MalformedPackageURLException ex) {
208-
LOGGER.debug("Unable to build package url for openssl", ex);
209-
final GenericIdentifier id = new GenericIdentifier("generic:openssl@" + version, Confidence.HIGHEST);
210-
dependency.addSoftwareIdentifier(id);
206+
final Matcher strMatcher = VERSION_STR_PATTERN.matcher(contents);
207+
if (strMatcher.find()) {
208+
version = strMatcher.group(1);
209+
} else {
210+
final Matcher matcher = VERSION_PATTERN.matcher(contents);
211+
if (matcher.find()) {
212+
version = getOpenSSLVersion(Long.parseLong(matcher.group(1), HEXADECIMAL));
211213
}
212-
213214
}
214215
}
215-
if (found) {
216+
if (version != null) {
217+
dependency.addEvidence(EvidenceType.VERSION, OPENSSLV_H, "Version Constant",
218+
version, Confidence.HIGH);
219+
try {
220+
final PackageURL purl = PackageURLBuilder.aPackageURL().withType("generic")
221+
.withName("openssl").withVersion(version).build();
222+
dependency.addSoftwareIdentifier(new PurlIdentifier(purl, Confidence.HIGHEST));
223+
} catch (MalformedPackageURLException ex) {
224+
LOGGER.debug("Unable to build package url for openssl", ex);
225+
final GenericIdentifier id = new GenericIdentifier("generic:openssl@" + version, Confidence.HIGHEST);
226+
dependency.addSoftwareIdentifier(id);
227+
}
216228
dependency.setDisplayFileName(parentName + File.separatorChar + OPENSSLV_H);
217229
dependency.addEvidence(EvidenceType.VENDOR, OPENSSLV_H, "Vendor", "OpenSSL", Confidence.HIGHEST);
218230
dependency.addEvidence(EvidenceType.PRODUCT, OPENSSLV_H, "Product", "OpenSSL", Confidence.HIGHEST);

core/src/test/java/org/owasp/dependencycheck/analyzer/OpenSSLAnalyzerTest.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,4 +115,15 @@ void testOpenSSLVersionHeaderFile() throws AnalysisException {
115115
assertThat(result.getEvidence(EvidenceType.VENDOR).toString(), containsString("OpenSSL"));
116116
assertThat(result.getEvidence(EvidenceType.VERSION).toString(), containsString("1.0.2c"));
117117
}
118+
119+
@Test
120+
void testOpenSSL3xVersionHeaderFile() throws AnalysisException {
121+
final Dependency result = new Dependency(BaseTest.getResourceAsFile(
122+
this,
123+
"openssl-3x/opensslv.h"));
124+
analyzer.analyze(result, null);
125+
assertThat(result.getEvidence(EvidenceType.PRODUCT).toString(), containsString("OpenSSL"));
126+
assertThat(result.getEvidence(EvidenceType.VENDOR).toString(), containsString("OpenSSL"));
127+
assertThat(result.getEvidence(EvidenceType.VERSION).toString(), containsString("3.5.6"));
128+
}
118129
}
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
/*
2+
* WARNING: do not edit!
3+
* Generated by Makefile from include/openssl/opensslv.h.in
4+
*
5+
* Copyright 1999-2025 The OpenSSL Project Authors. All Rights Reserved.
6+
*
7+
* Licensed under the Apache License 2.0 (the "License"). You may not use
8+
* this file except in compliance with the License. You can obtain a copy
9+
* in the file LICENSE in the source distribution or at
10+
* https://www.openssl.org/source/license.html
11+
*/
12+
13+
#ifndef OPENSSL_OPENSSLV_H
14+
#define OPENSSL_OPENSSLV_H
15+
#pragma once
16+
17+
#ifdef __cplusplus
18+
extern "C" {
19+
#endif
20+
21+
/*
22+
* SECTION 1: VERSION DATA. These will change for each release
23+
*/
24+
25+
/*
26+
* Base version macros
27+
*
28+
* These macros express version number MAJOR.MINOR.PATCH exactly
29+
*/
30+
/* clang-format off */
31+
# define OPENSSL_VERSION_MAJOR 3
32+
/* clang-format on */
33+
/* clang-format off */
34+
# define OPENSSL_VERSION_MINOR 5
35+
/* clang-format on */
36+
/* clang-format off */
37+
# define OPENSSL_VERSION_PATCH 6
38+
/* clang-format on */
39+
40+
/*
41+
* Additional version information
42+
*
43+
* These are also part of the new version scheme, but aren't part
44+
* of the version number itself.
45+
*/
46+
47+
/* Could be: #define OPENSSL_VERSION_PRE_RELEASE "-alpha.1" */
48+
/* clang-format off */
49+
# define OPENSSL_VERSION_PRE_RELEASE ""
50+
/* clang-format on */
51+
/* Could be: #define OPENSSL_VERSION_BUILD_METADATA "+fips" */
52+
/* Could be: #define OPENSSL_VERSION_BUILD_METADATA "+vendor.1" */
53+
/* clang-format off */
54+
# define OPENSSL_VERSION_BUILD_METADATA ""
55+
/* clang-format on */
56+
57+
/*
58+
* Note: The OpenSSL Project will never define OPENSSL_VERSION_BUILD_METADATA
59+
* to be anything but the empty string. Its use is entirely reserved for
60+
* others
61+
*/
62+
63+
/*
64+
* Shared library version
65+
*
66+
* This is strictly to express ABI version, which may or may not
67+
* be related to the API version expressed with the macros above.
68+
* This is defined in free form.
69+
*/
70+
/* clang-format off */
71+
# define OPENSSL_SHLIB_VERSION 3
72+
/* clang-format on */
73+
74+
/*
75+
* SECTION 2: USEFUL MACROS
76+
*/
77+
78+
/* For checking general API compatibility when preprocessing */
79+
#define OPENSSL_VERSION_PREREQ(maj, min) \
80+
((OPENSSL_VERSION_MAJOR << 16) + OPENSSL_VERSION_MINOR >= ((maj) << 16) + (min))
81+
82+
/*
83+
* Macros to get the version in easily digested string form, both the short
84+
* "MAJOR.MINOR.PATCH" variant (where MAJOR, MINOR and PATCH are replaced
85+
* with the values from the corresponding OPENSSL_VERSION_ macros) and the
86+
* longer variant with OPENSSL_VERSION_PRE_RELEASE_STR and
87+
* OPENSSL_VERSION_BUILD_METADATA_STR appended.
88+
*/
89+
/* clang-format off */
90+
# define OPENSSL_VERSION_STR "3.5.6"
91+
/* clang-format on */
92+
/* clang-format off */
93+
# define OPENSSL_FULL_VERSION_STR "3.5.6"
94+
/* clang-format on */
95+
96+
/*
97+
* SECTION 3: ADDITIONAL METADATA
98+
*
99+
* These strings are defined separately to allow them to be parsable.
100+
*/
101+
/* clang-format off */
102+
# define OPENSSL_RELEASE_DATE "7 Apr 2026"
103+
/* clang-format on */
104+
105+
/*
106+
* SECTION 4: BACKWARD COMPATIBILITY
107+
*/
108+
109+
/* clang-format off */
110+
# define OPENSSL_VERSION_TEXT "OpenSSL 3.5.6 7 Apr 2026"
111+
/* clang-format on */
112+
113+
/* clang-format off */
114+
/* Synthesize OPENSSL_VERSION_NUMBER with the layout 0xMNN00PP0L */
115+
# define OPENSSL_VERSION_NUMBER \
116+
( (OPENSSL_VERSION_MAJOR<<28) \
117+
|(OPENSSL_VERSION_MINOR<<20) \
118+
|(OPENSSL_VERSION_PATCH<<4) \
119+
|0x0L )
120+
/* clang-format on */
121+
122+
#ifdef __cplusplus
123+
}
124+
#endif
125+
126+
#include <openssl/macros.h>
127+
#ifndef OPENSSL_NO_DEPRECATED_3_0
128+
#define HEADER_OPENSSLV_H
129+
#endif
130+
131+
#endif /* OPENSSL_OPENSSLV_H */

0 commit comments

Comments
 (0)