Skip to content

Commit 72e5abb

Browse files
committed
SDK-1019: Parse unknown anchors
1 parent b4b3728 commit 72e5abb

File tree

4 files changed

+82
-50
lines changed

4 files changed

+82
-50
lines changed

src/Yoti/Entity/Anchor.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,10 @@ class Anchor
1515
{
1616
const TYPE_SOURCE_NAME = 'Source';
1717
const TYPE_VERIFIER_NAME = 'Verifier';
18+
const TYPE_UNKNOWN_NAME = 'UNKNOWN';
1819
const TYPE_SOURCE_OID = '1.3.6.1.4.1.47127.1.1.1';
1920
const TYPE_VERIFIER_OID = '1.3.6.1.4.1.47127.1.1.2';
21+
const TYPE_UNKNOWN_OID = '';
2022

2123
/**
2224
* @var string

src/Yoti/Util/Profile/AnchorConverter.php

Lines changed: 64 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -11,54 +11,64 @@
1111
class AnchorConverter
1212
{
1313
/**
14-
* Convert Protobuf Anchor to a map of oid -> Yoti Anchor
14+
* Convert Protobuf Anchor to a map of oid -> Yoti Anchors
1515
*
1616
* @param Anchor $anchor
1717
*
18-
* @return array|null
18+
* @return array map of oid => YotiAnchor[]
1919
*/
20-
public static function convert(Anchor $protobufAnchor)
20+
public static function convertAnchors(Anchor $protobufAnchor)
2121
{
22-
$anchorMap = null;
23-
$ASN1 = new ASN1();
24-
$X509 = new X509();
22+
$anchorMap = [];
2523
$anchorSubType = $protobufAnchor->getSubType();
2624
$yotiSignedTimeStamp = self::convertToYotiSignedTimestamp($protobufAnchor);
27-
$X509CertsList = self::convertCertsListToX509($X509, $protobufAnchor->getOriginServerCerts());
28-
$anchorTypesMap = self::getAnchorTypesMap();
25+
$X509CertsList = self::convertCertsListToX509($protobufAnchor->getOriginServerCerts());
2926

3027
foreach ($X509CertsList as $certX509Obj) {
3128
$certExtsArr = $certX509Obj->tbsCertificate->extensions;
3229

33-
foreach ($anchorTypesMap as $oid => $anchorType) {
34-
foreach ($certExtsArr as $extObj) {
35-
$extArr = (array) $extObj;
36-
$oidFound = array_search($oid, $extArr, true);
37-
if ($oidFound !== false && is_string($extArr['extnValue'])) {
38-
$extEncodedValue = $extArr['extnValue'];
39-
40-
if ($decodedAnchorValue = self::decodeAnchorValue($ASN1, $X509, $extEncodedValue)) {
41-
$yotiAnchor = self::createYotiAnchor(
42-
$decodedAnchorValue,
43-
$anchorType,
44-
$anchorSubType,
45-
$yotiSignedTimeStamp,
46-
$X509CertsList
47-
);
48-
$anchorMap = [
49-
'oid' => $oid,
50-
'yoti_anchor' => $yotiAnchor
51-
];
52-
// We are only looking for one YotiAnchor from protobufAnchor
53-
return $anchorMap;
54-
}
55-
}
30+
foreach ($certExtsArr as $extObj) {
31+
$anchorType = self::getAnchorTypeByOid($extObj->extnId);
32+
$anchorValue = '';
33+
if ($anchorType !== YotiAnchor::TYPE_UNKNOWN_NAME) {
34+
$anchorValue = self::decodeAnchorValue($extObj->extnValue);
5635
}
36+
$yotiAnchor = self::createYotiAnchor(
37+
$anchorValue,
38+
$anchorType,
39+
$anchorSubType,
40+
$yotiSignedTimeStamp,
41+
$X509CertsList
42+
);
43+
$mapKey = self::getAnchorTypeKey($anchorType);
44+
$anchorMap[$mapKey][] = $yotiAnchor;
5745
}
5846
}
5947
return $anchorMap;
6048
}
6149

50+
/**
51+
* Convert Protobuf Anchor to a map of oid -> Yoti Anchor
52+
*
53+
* @deprecated no longer in use.
54+
*
55+
* @param Anchor $anchor
56+
*
57+
* @return array|null
58+
*/
59+
public static function convert(Anchor $protobufAnchor)
60+
{
61+
$extensions = self::convertAnchors($protobufAnchor);
62+
foreach (array_keys(self::getAnchorTypesMap()) as $oid) {
63+
if (isset($extensions[$oid][0])) {
64+
return [
65+
'oid' => $oid,
66+
'yoti_anchor' => $extensions[$oid][0],
67+
];
68+
}
69+
}
70+
}
71+
6272
/**
6373
* @param string $value
6474
* @param string $type
@@ -80,14 +90,14 @@ private static function createYotiAnchor($value, $type, $subType, $signedTimesta
8090
}
8191

8292
/**
83-
* @param ASN1 $ASN1
84-
* @param X509 $X509
8593
* @param $extEncodedValue
8694
*
8795
* @return null|string
8896
*/
89-
private static function decodeAnchorValue(ASN1 $ASN1, X509 $X509, $extEncodedValue)
97+
private static function decodeAnchorValue($extEncodedValue)
9098
{
99+
$X509 = new X509();
100+
$ASN1 = new ASN1();
91101
$encodedBER = $X509->_extractBER($extEncodedValue);
92102
$decodedValArr = $ASN1->decodeBER($encodedBER);
93103
if (isset($decodedValArr[0]['content'][0]['content'])) {
@@ -124,16 +134,15 @@ private static function convertToYotiSignedTimestamp(Anchor $anchor)
124134
}
125135

126136
/**
127-
* @param X509 $X509
128137
* @param Traversable $certificateList
129138
*
130139
* @return array
131140
*/
132-
private static function convertCertsListToX509(X509 $X509, Traversable $certificateList)
141+
private static function convertCertsListToX509(Traversable $certificateList)
133142
{
134143
$certsList = [];
135144
foreach ($certificateList as $certificate) {
136-
if ($X509CertObj = self::convertCertToX509($X509, $certificate)) {
145+
if ($X509CertObj = self::convertCertToX509($certificate)) {
137146
$certsList[] = $X509CertObj;
138147
}
139148
}
@@ -143,26 +152,39 @@ private static function convertCertsListToX509(X509 $X509, Traversable $certific
143152
/**
144153
* Return X509 Cert Object.
145154
*
146-
* @param X509 $X509
147155
* @param $certificate
148156
*
149157
* @return \stdClass
150158
*/
151-
private static function convertCertToX509(X509 $X509, $certificate)
159+
private static function convertCertToX509($certificate)
152160
{
161+
$X509 = new X509();
153162
$X509Data = $X509->loadX509($certificate);
154163
return json_decode(json_encode($X509Data), false);
155164
}
156165

157166
/**
167+
* Get anchor type by OID.
168+
*
158169
* @param string $oid
159170
*
160171
* @return string
161172
*/
162173
private static function getAnchorTypeByOid($oid)
163174
{
164-
$anchorTypesMap = self::getAnchorTypesMap();
165-
return isset($anchorTypesMap[$oid]) ? $anchorTypesMap[$oid] : 'Unknown';
175+
return self::getAnchorTypesMap()[$oid] ?: YotiAnchor::TYPE_UNKNOWN_NAME;
176+
}
177+
178+
/**
179+
* Get anchor type key by type.
180+
*
181+
* @param string $type
182+
*
183+
* @return string
184+
*/
185+
private static function getAnchorTypeKey($type)
186+
{
187+
return array_flip(self::getAnchorTypesMap())[$type] ?: YotiAnchor::TYPE_UNKNOWN_NAME;
166188
}
167189

168190
/**
@@ -173,6 +195,7 @@ private static function getAnchorTypesMap()
173195
return [
174196
YotiAnchor::TYPE_SOURCE_OID => YotiAnchor::TYPE_SOURCE_NAME,
175197
YotiAnchor::TYPE_VERIFIER_OID => YotiAnchor::TYPE_VERIFIER_NAME,
198+
YotiAnchor::TYPE_UNKNOWN_OID => YotiAnchor::TYPE_UNKNOWN_NAME,
176199
];
177200
}
178201
}

src/Yoti/Util/Profile/AnchorListConverter.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,11 @@ public static function convert(Traversable $anchorList)
1111
$yotiAnchorsMap = [];
1212

1313
foreach ($anchorList as $protobufAnchor) {
14-
if ($parsedAnchor = AnchorConverter::convert($protobufAnchor)) {
15-
$yotiAnchorsMap[$parsedAnchor['oid']][] = $parsedAnchor['yoti_anchor'];
14+
if ($parsedAnchors = AnchorConverter::convertAnchors($protobufAnchor)) {
15+
$yotiAnchorsMap = array_merge_recursive($yotiAnchorsMap, $parsedAnchors);
1616
}
1717
}
18+
1819
return $yotiAnchorsMap;
1920
}
2021
}

tests/Entity/AttributeTest.php

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -93,13 +93,19 @@ public function testVerifiers()
9393
public function testGetAnchors()
9494
{
9595
$anchors = $this->dummyAttribute->getAnchors();
96-
$this->assertEquals(3, count($anchors));
97-
$this->assertEquals(YotiAnchor::TYPE_SOURCE_NAME, $anchors[0]->getType());
98-
$this->assertEquals('DRIVING_LICENCE', $anchors[0]->getValue());
99-
$this->assertEquals(YotiAnchor::TYPE_SOURCE_NAME, $anchors[1]->getType());
100-
$this->assertEquals('PASSPORT', $anchors[1]->getValue());
101-
$this->assertEquals(YotiAnchor::TYPE_VERIFIER_NAME, $anchors[2]->getType());
102-
$this->assertEquals('YOTI_ADMIN', $anchors[2]->getValue());
96+
$this->assertEquals(6, count($anchors));
97+
$this->assertEquals(YotiAnchor::TYPE_UNKNOWN_NAME, $anchors[0]->getType());
98+
$this->assertEquals('', $anchors[0]->getValue());
99+
$this->assertEquals(YotiAnchor::TYPE_UNKNOWN_NAME, $anchors[1]->getType());
100+
$this->assertEquals('', $anchors[1]->getValue());
101+
$this->assertEquals(YotiAnchor::TYPE_UNKNOWN_NAME, $anchors[2]->getType());
102+
$this->assertEquals('', $anchors[2]->getValue());
103+
$this->assertEquals(YotiAnchor::TYPE_SOURCE_NAME, $anchors[3]->getType());
104+
$this->assertEquals('DRIVING_LICENCE', $anchors[3]->getValue());
105+
$this->assertEquals(YotiAnchor::TYPE_SOURCE_NAME, $anchors[4]->getType());
106+
$this->assertEquals('PASSPORT', $anchors[4]->getValue());
107+
$this->assertEquals(YotiAnchor::TYPE_VERIFIER_NAME, $anchors[5]->getType());
108+
$this->assertEquals('YOTI_ADMIN', $anchors[5]->getValue());
103109
}
104110

105111
/**

0 commit comments

Comments
 (0)