@@ -38,6 +38,13 @@ class OneLogin_Saml2_Response
3838 */
3939 public $ encrypted = false ;
4040
41+ /**
42+ * The response contains an encrypted nameId in the assertion.
43+ *
44+ * @var bool
45+ */
46+ public $ encryptedNameId = false ;
47+
4148 /**
4249 * After validation, if it fail this var has the cause of the problem
4350 * @var string
@@ -200,14 +207,12 @@ public function isValid($requestId = null)
200207 );
201208 }
202209
203- if ($ security ['wantNameIdEncrypted ' ]) {
204- $ encryptedIdNodes = $ this ->_queryAssertion ('/saml:Subject/saml:EncryptedID/xenc:EncryptedData ' );
205- if ($ encryptedIdNodes ->length != 1 ) {
206- throw new OneLogin_Saml2_ValidationError (
207- "The NameID of the Response is not encrypted and the SP requires it " ,
208- OneLogin_Saml2_ValidationError::NO_ENCRYPTED_NAMEID
209- );
210- }
210+ $ this ->encryptedNameId = $ this ->encryptedNameId || $ this ->_queryAssertion ('/saml:Subject/saml:EncryptedID/xenc:EncryptedData ' )->length > 0 ;
211+ if (!$ this ->encryptedNameId && $ security ['wantNameIdEncrypted ' ]) {
212+ throw new OneLogin_Saml2_ValidationError (
213+ "The NameID of the Response is not encrypted and the SP requires it " ,
214+ OneLogin_Saml2_ValidationError::NO_ENCRYPTED_NAMEID
215+ );
211216 }
212217
213218 // Validate Conditions element exists
@@ -366,17 +371,6 @@ public function isValid($requestId = null)
366371 }
367372 }
368373
369- // Detect case not supported
370- if ($ this ->encrypted ) {
371- $ encryptedIDNodes = OneLogin_Saml2_Utils::query ($ this ->decryptedDocument , '/samlp:Response/saml:Assertion/saml:Subject/saml:EncryptedID ' );
372- if ($ encryptedIDNodes ->length > 0 ) {
373- throw new OneLogin_Saml2_ValidationError (
374- 'SAML Response that contains a an encrypted Assertion with encrypted nameId is not supported. ' ,
375- OneLogin_Saml2_ValidationError::NOT_SUPPORTED
376- );
377- }
378- }
379-
380374 if (empty ($ signedElements ) || (!$ hasSignedResponse && !$ hasSignedAssertion )) {
381375 throw new OneLogin_Saml2_ValidationError (
382376 'No Signature found. SAML Response rejected ' ,
@@ -585,9 +579,15 @@ public function getNameIdData()
585579 if ($ encryptedIdDataEntries ->length == 1 ) {
586580 $ encryptedData = $ encryptedIdDataEntries ->item (0 );
587581
588- $ key = $ this ->_settings ->getSPkey ();
582+ $ pem = $ this ->_settings ->getSPkey ();
583+ if (empty ($ pem )) {
584+ throw new OneLogin_Saml2_Error (
585+ "No private key available, check settings " ,
586+ OneLogin_Saml2_Error::PRIVATE_KEY_NOT_FOUND
587+ );
588+ }
589589 $ seckey = new XMLSecurityKey (XMLSecurityKey::RSA_1_5 , array ('type ' =>'private ' ));
590- $ seckey ->loadKey ($ key );
590+ $ seckey ->loadKey ($ pem );
591591
592592 $ nameId = OneLogin_Saml2_Utils::decryptElement ($ encryptedData , $ seckey );
593593
@@ -1139,6 +1139,17 @@ protected function _decryptAssertion($dom)
11391139 if ($ check === false ) {
11401140 throw new Exception ('Error: string from decrypted assertion could not be loaded into a XML document ' );
11411141 }
1142+
1143+ // check if the decrypted assertion contains an encryptedID
1144+ $ encryptedID = $ decrypted ->getElementsByTagName ('EncryptedID ' )->item (0 );
1145+ if ($ encryptedID ) {
1146+ // decrypt the encryptedID
1147+ $ this ->encryptedNameId = true ;
1148+ $ encryptedData = $ encryptedID ->getElementsByTagName ('EncryptedData ' )->item (0 );
1149+ $ nameId = $ this ->decryptNameId ($ encryptedData , $ pem );
1150+ OneLogin_Saml2_Utils::treeCopyReplace ($ encryptedID , $ nameId );
1151+ }
1152+
11421153 if ($ encData ->parentNode instanceof DOMDocument) {
11431154 return $ decrypted ;
11441155 } else {
@@ -1171,6 +1182,46 @@ protected function _decryptAssertion($dom)
11711182 }
11721183 }
11731184
1185+ /**
1186+ * Decrypt EncryptedID element
1187+ *
1188+ * @param \DOMElement $encryptedData The encrypted data.
1189+ * @param string $key The private key
1190+ *
1191+ * @return \DOMElement The decrypted element.
1192+ *
1193+ * @throws OneLogin_Saml2_Error
1194+ * @throws OneLogin_Saml2_ValidationError
1195+ */
1196+ private function decryptNameId (\DOMElement $ encryptedData , string $ pem )
1197+ {
1198+ $ objenc = new XMLSecEnc ();
1199+ $ encData = $ objenc ->locateEncryptedData ($ encryptedData );
1200+ $ objenc ->setNode ($ encData );
1201+ $ objenc ->type = $ encData ->getAttribute ("Type " );
1202+ if (!$ objKey = $ objenc ->locateKey ()) {
1203+ throw new OneLogin_Saml2_ValidationError (
1204+ "Unknown algorithm " ,
1205+ ValidationError::KEY_ALGORITHM_ERROR
1206+ );
1207+ }
1208+ $ key = null ;
1209+ if ($ objKeyInfo = $ objenc ->locateKeyInfo ($ objKey )) {
1210+ if ($ objKeyInfo ->isEncrypted ) {
1211+ $ objencKey = $ objKeyInfo ->encryptedCtx ;
1212+ $ objKeyInfo ->loadKey ($ pem , false , false );
1213+ $ key = $ objencKey ->decryptKey ($ objKeyInfo );
1214+ } else {
1215+ // symmetric encryption key support
1216+ $ objKeyInfo ->loadKey ($ pem , false , false );
1217+ }
1218+ }
1219+ if (empty ($ objKey ->key )) {
1220+ $ objKey ->loadKey ($ key );
1221+ }
1222+ return OneLogin_Saml2_Utils::decryptElement ($ encryptedData , $ objKey );
1223+ }
1224+
11741225 /**
11751226 * After execute a validation process, if fails this method returns the cause
11761227 *
0 commit comments