@@ -58,6 +58,11 @@ namespace IO.Swagger.Controllers;
5858using Contracts . Security ;
5959using System . Text . Json . Serialization ;
6060using 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