Skip to content

Commit 8a0b5ab

Browse files
committed
Add /submodel/$sign
1 parent 1dfcbd3 commit 8a0b5ab

1 file changed

Lines changed: 114 additions & 0 deletions

File tree

src/IO.Swagger.Lib.V3/Controllers/SubmodelRepositoryAPIApi.cs

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,11 @@ namespace IO.Swagger.Controllers;
5858
using Contracts.Security;
5959
using System.Text.Json.Serialization;
6060
using System.Text.Json;
61+
using System.Security.Cryptography.X509Certificates;
62+
using System.Security.Cryptography.Xml;
63+
using System.Security.Cryptography;
64+
using System.Text;
65+
using System.Text.Json.Nodes;
6166

6267
/// <summary>
6368
///
@@ -1341,6 +1346,115 @@ public async virtual Task<IActionResult> GetSubmodelById([FromRoute][Required] s
13411346
return new ObjectResult(output);
13421347
}
13431348

1349+
/// <summary>
1350+
/// Returns a specific Submodel signed
1351+
/// </summary>
1352+
/// <param name="submodelIdentifier">The Submodel’s unique id (UTF8-BASE64-URL-encoded)</param>
1353+
/// <param name="level">Determines the structural depth of the respective resource content</param>
1354+
/// <param name="extent">Determines to which extent the resource is being serialized</param>
1355+
/// <response code="200">Requested Submodel</response>
1356+
/// <response code="400">Bad Request, e.g. the request parameters of the format of the request body is wrong.</response>
1357+
/// <response code="401">Unauthorized, e.g. the server refused the authorization attempt.</response>
1358+
/// <response code="403">Forbidden</response>
1359+
/// <response code="404">Not Found</response>
1360+
/// <response code="500">Internal Server Error</response>
1361+
/// <response code="0">Default error handling for unmentioned status codes</response>
1362+
[HttpGet]
1363+
[Route("submodels/{submodelIdentifier}/$sign")]
1364+
[ValidateModelState]
1365+
[SwaggerOperation("GetSubmodelByIdSigned")]
1366+
[SwaggerResponse(statusCode: 200, type: typeof(Submodel), description: "Requested Submodel")]
1367+
[SwaggerResponse(statusCode: 400, type: typeof(Result), description: "Bad Request, e.g. the request parameters of the format of the request body is wrong.")]
1368+
[SwaggerResponse(statusCode: 401, type: typeof(Result), description: "Unauthorized, e.g. the server refused the authorization attempt.")]
1369+
[SwaggerResponse(statusCode: 403, type: typeof(Result), description: "Forbidden")]
1370+
[SwaggerResponse(statusCode: 404, type: typeof(Result), description: "Not Found")]
1371+
[SwaggerResponse(statusCode: 500, type: typeof(Result), description: "Internal Server Error")]
1372+
[SwaggerResponse(statusCode: 0, type: typeof(Result), description: "Default error handling for unmentioned status codes")]
1373+
public async virtual Task<IActionResult> GetSubmodelByIdSigned([FromRoute][Required] string submodelIdentifier, [FromQuery] string? level, [FromQuery] string? extent)
1374+
{
1375+
//Validate level and extent
1376+
var levelEnum = _validateModifierService.ValidateLevel(level);
1377+
var extentEnum = _validateModifierService.ValidateExtent(extent);
1378+
1379+
var decodedSubmodelIdentifier = _decoderService.Decode("submodelIdentifier", submodelIdentifier);
1380+
1381+
_logger.LogInformation($"Received request to get the submodel with id {decodedSubmodelIdentifier}");
1382+
if (decodedSubmodelIdentifier == null)
1383+
{
1384+
throw new NotAllowed($"Cannot proceed as {nameof(decodedSubmodelIdentifier)} is null");
1385+
}
1386+
1387+
var securityConfig = new SecurityConfig(Program.noSecurity, this);
1388+
1389+
var submodel = await _dbRequestHandlerService.ReadSubmodelById(securityConfig, null, decodedSubmodelIdentifier);
1390+
1391+
string certFile = "Andreas_Orzelski_Chain.pfx";
1392+
string certPW = "i40";
1393+
if (System.IO.File.Exists(certFile))
1394+
{
1395+
var submodelText = Jsonization.Serialize.ToJsonObject(submodel).ToJsonString();
1396+
1397+
var mStrm = new MemoryStream(Encoding.UTF8.GetBytes(submodelText));
1398+
var node = System.Text.Json.JsonSerializer.DeserializeAsync<JsonNode>(mStrm).Result;
1399+
var s = Jsonization.Deserialize.SubmodelFrom(node);
1400+
1401+
submodel.Extensions ??= [];
1402+
using (var certificate = new X509Certificate2(certFile, certPW))
1403+
{
1404+
if (certificate == null)
1405+
{
1406+
throw new NotAllowed($"");
1407+
}
1408+
1409+
X509Certificate2Collection xc = new X509Certificate2Collection();
1410+
xc.Import(certFile, certPW, X509KeyStorageFlags.PersistKeySet);
1411+
1412+
var x5cString = "";
1413+
for (var j = xc.Count - 1; j >= 0; j--)
1414+
{
1415+
var c = Convert.ToBase64String(xc[j].GetRawCertData());
1416+
if (x5cString != "")
1417+
{
1418+
x5cString += ", ";
1419+
}
1420+
x5cString += c;
1421+
}
1422+
1423+
var signature = "";
1424+
try
1425+
{
1426+
using (RSA rsa = certificate.GetRSAPrivateKey())
1427+
{
1428+
if (rsa == null)
1429+
{
1430+
throw new NotAllowed($"");
1431+
}
1432+
1433+
var data = Encoding.UTF8.GetBytes(submodelText);
1434+
var signed = rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
1435+
signature = Convert.ToBase64String(signed);
1436+
}
1437+
}
1438+
// ReSharper disable EmptyGeneralCatchClause
1439+
catch
1440+
{
1441+
}
1442+
1443+
submodel.Extensions.Add(new Extension("$signed", value: ""));
1444+
submodel.Extensions.Add(new Extension("$signed_submodel", value: submodelText));
1445+
submodel.Extensions.Add(new Extension("$signed_algorithm", value: "RS256"));
1446+
submodel.Extensions.Add(new Extension("$signed_x5c", value: x5cString));
1447+
submodel.Extensions.Add(new Extension("$signed_signature", value: signature));
1448+
1449+
submodel.SubmodelElements = [];
1450+
1451+
return new ObjectResult(submodel);
1452+
}
1453+
}
1454+
1455+
throw new NotAllowed($"");
1456+
}
1457+
13441458
/// <summary>
13451459
/// Returns the metadata attributes of a specific Submodel
13461460
/// </summary>

0 commit comments

Comments
 (0)