aboutsummaryrefslogtreecommitdiffstats
path: root/meta-networking/recipes-support/open-vm-tools/open-vm-tools/CVE-2023-34058.patch
blob: d24dd3695c1e278c9187ab8db037acb805ed7955 (plain)
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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
From 6822b5a84f8cfa60d46479d6b8f1c63eb85eac87 Mon Sep 17 00:00:00 2001
From: John Wolfe <jwolfe@vmware.com>
Date: Wed, 18 Oct 2023 09:04:07 -0700
Subject: [PATCH] Address CVE-2023-34058

VGAuth: don't accept tokens with unrelated certs.

CVE: CVE-2023-34058

Upstream-Status: Backport [https://github.com/vmware/open-vm-tools/commit/e5be40b9cc025d03ccd5689ef9192d29abd68bfe]

Signed-off-by: Archana Polampalli <archana.polampalli@windriver.com>
---
 open-vm-tools/vgauth/common/certverify.c      | 145 ++++++++++++++++++
 open-vm-tools/vgauth/common/certverify.h      |   4 +
 open-vm-tools/vgauth/common/prefs.h           |   2 +
 .../vgauth/serviceImpl/saml-xmlsec1.c         |  14 ++
 4 files changed, 165 insertions(+)

diff --git a/open-vm-tools/vgauth/common/certverify.c b/open-vm-tools/vgauth/common/certverify.c
index edf54928..29b12df3 100644
--- a/open-vm-tools/vgauth/common/certverify.c
+++ b/open-vm-tools/vgauth/common/certverify.c
@@ -893,3 +893,148 @@ done:

    return err;
 }
+
+
+/*
+ * Finds a cert with a subject (if checkSubj is set) or issuer (if
+ * checkSUbj is unset), matching 'val' in the list
+ * of certs.  Returns a match or NULL.
+ */
+
+static X509 *
+FindCert(GList *cList,
+         X509_NAME *val,
+         int checkSubj)
+{
+   GList *l;
+   X509 *c;
+   X509_NAME *v;
+
+   l = cList;
+   while (l != NULL) {
+      c = (X509 *) l->data;
+      if (checkSubj) {
+         v = X509_get_subject_name(c);
+      } else {
+         v = X509_get_issuer_name(c);
+      }
+      if (X509_NAME_cmp(val, v) == 0) {
+         return c;
+      }
+      l = l->next;
+   }
+   return NULL;
+}
+
+
+/*
+ ******************************************************************************
+ * CertVerify_CheckForUnrelatedCerts --                                  */ /**
+ *
+ * Looks over a list of certs.  If it finds that they are not all
+ * part of the same chain, returns failure.
+ *
+ * @param[in]     numCerts      The number of certs in the chain.
+ * @param[in]     pemCerts      The chain of certificates to verify.
+ *
+ * @return VGAUTH_E_OK on success, VGAUTH_E_FAIL if unrelated certs are found.
+ *
+ ******************************************************************************
+ */
+
+VGAuthError
+CertVerify_CheckForUnrelatedCerts(int numCerts,
+                                  const char **pemCerts)
+{
+   VGAuthError err = VGAUTH_E_FAIL;
+   int chainLen = 0;
+   int i;
+   X509 **certs = NULL;
+   GList *rawList = NULL;
+   X509 *baseCert;
+   X509 *curCert;
+   X509_NAME *subject;
+   X509_NAME *issuer;
+
+   /* common single cert case; nothing to do */
+   if (numCerts == 1) {
+      return VGAUTH_E_OK;
+   }
+
+   /* convert all PEM to X509 objects */
+   certs = g_malloc0(numCerts * sizeof(X509 *));
+   for (i = 0; i < numCerts; i++) {
+      certs[i] = CertStringToX509(pemCerts[i]);
+      if (NULL == certs[i]) {
+         g_warning("%s: failed to convert cert to X509\n", __FUNCTION__);
+         goto done;
+      }
+   }
+
+   /* choose the cert to start the chain.  shouldn't matter which */
+   baseCert = certs[0];
+
+   /* put the rest into a list */
+   for (i = 1; i < numCerts; i++) {
+      rawList = g_list_append(rawList, certs[i]);
+   }
+
+   /* now chase down to a leaf, looking for certs the baseCert issued */
+   subject = X509_get_subject_name(baseCert);
+   while ((curCert = FindCert(rawList, subject, 0)) != NULL) {
+      /* pull it from the list */
+      rawList = g_list_remove(rawList, curCert);
+      /* set up the next find */
+      subject = X509_get_subject_name(curCert);
+   }
+
+   /*
+    * walk up to the root cert, by finding a cert where the
+    * issuer equals the subject of the current
+    */
+   issuer = X509_get_issuer_name(baseCert);
+   while ((curCert = FindCert(rawList, issuer, 1)) != NULL) {
+      /* pull it from the list */
+      rawList = g_list_remove(rawList, curCert);
+      /* set up the next find */
+      issuer = X509_get_issuer_name(curCert);
+   }
+
+   /*
+    * At this point, anything on the list should be certs that are not part
+    * of the chain that includes the original 'baseCert'.
+    *
+    * For a valid token, the list should be empty.
+    */
+   chainLen = g_list_length(rawList);
+   if (chainLen != 0 ) {
+      GList *l;
+
+      g_warning("%s: %d unrelated certs found in list\n",
+                __FUNCTION__, chainLen);
+
+      /* debug helper */
+      l = rawList;
+      while (l != NULL) {
+         X509* c = (X509 *) l->data;
+         char *s = X509_NAME_oneline(X509_get_subject_name(c), NULL, 0);
+
+         g_debug("%s: unrelated cert subject: %s\n", __FUNCTION__, s);
+         free(s);
+         l = l->next;
+      }
+
+      goto done;
+   }
+
+   g_debug("%s: Success!  no unrelated certs found\n", __FUNCTION__);
+   err = VGAUTH_E_OK;
+
+done:
+   g_list_free(rawList);
+   for (i = 0; i < numCerts; i++) {
+      X509_free(certs[i]);
+   }
+   g_free(certs);
+   return err;
+}
diff --git a/open-vm-tools/vgauth/common/certverify.h b/open-vm-tools/vgauth/common/certverify.h
index d7c6410b..f582bb82 100644
--- a/open-vm-tools/vgauth/common/certverify.h
+++ b/open-vm-tools/vgauth/common/certverify.h
@@ -67,6 +67,10 @@ VGAuthError CertVerify_CheckSignatureUsingCert(VGAuthHashAlg hash,
                                                size_t signatureLen,
                                                const unsigned char *signature);

+
+VGAuthError CertVerify_CheckForUnrelatedCerts(int numCerts,
+                                              const char **pemCerts);
+
 gchar * CertVerify_StripPEMCert(const gchar *pemCert);

 gchar * CertVerify_CertToX509String(const gchar *pemCert);
diff --git a/open-vm-tools/vgauth/common/prefs.h b/open-vm-tools/vgauth/common/prefs.h
index ff116928..87ccc9b3 100644
--- a/open-vm-tools/vgauth/common/prefs.h
+++ b/open-vm-tools/vgauth/common/prefs.h
@@ -136,6 +136,8 @@ msgCatalog = /etc/vmware-tools/vgauth/messages
 #define VGAUTH_PREF_ALIASSTORE_DIR         "aliasStoreDir"
 /** The number of seconds slack allowed in either direction in SAML token date checks. */
 #define VGAUTH_PREF_CLOCK_SKEW_SECS        "clockSkewAdjustment"
+/** If unrelated certificates are allowed in a SAML token */
+#define VGAUTH_PREF_ALLOW_UNRELATED_CERTS  "allowUnrelatedCerts"

 /** Ticket group name. */
 #define VGAUTH_PREF_GROUP_NAME_TICKET      "ticket"
diff --git a/open-vm-tools/vgauth/serviceImpl/saml-xmlsec1.c b/open-vm-tools/vgauth/serviceImpl/saml-xmlsec1.c
index aaa5082a..17b56de9 100644
--- a/open-vm-tools/vgauth/serviceImpl/saml-xmlsec1.c
+++ b/open-vm-tools/vgauth/serviceImpl/saml-xmlsec1.c
@@ -47,6 +47,7 @@
 #include "vmxlog.h"

 static int gClockSkewAdjustment = VGAUTH_PREF_DEFAULT_CLOCK_SKEW_SECS;
+static gboolean gAllowUnrelatedCerts = FALSE;
 static xmlSchemaPtr gParsedSchemas = NULL;
 static xmlSchemaValidCtxtPtr gSchemaValidateCtx = NULL;

@@ -313,6 +314,10 @@ LoadPrefs(void)
                                       VGAUTH_PREF_DEFAULT_CLOCK_SKEW_SECS);
     Log("%s: Allowing %d of clock skew for SAML date validation\n",
         __FUNCTION__, gClockSkewAdjustment);
+    gAllowUnrelatedCerts = Pref_GetBool(gPrefs,
+                                        VGAUTH_PREF_ALLOW_UNRELATED_CERTS,
+                                        VGAUTH_PREF_GROUP_NAME_SERVICE,
+                                        FALSE);
 }


@@ -1526,6 +1531,15 @@ SAML_VerifyBearerTokenAndChain(const char *xmlText,
    if (FALSE == bRet) {
       return VGAUTH_E_AUTHENTICATION_DENIED;
    }
+   if (!gAllowUnrelatedCerts) {
+      err = CertVerify_CheckForUnrelatedCerts(num, (const char **) certChain);
+      if (err != VGAUTH_E_OK) {
+         VMXLog_Log(VMXLOG_LEVEL_WARNING,
+                    "Unrelated certs found in SAML token, failing\n");
+         return VGAUTH_E_AUTHENTICATION_DENIED;
+      }
+   }
+

    subj.type = SUBJECT_TYPE_NAMED;
    subj.name = *subjNameOut;
--
2.40.0