From e0e6ac3038c92d1dd68062604d7acbb421fccbe2 Mon Sep 17 00:00:00 2001 From: Pelayo Torres Date: Tue, 18 Feb 2025 12:21:38 +0100 Subject: [PATCH 1/3] PSK --- .../controllers/default_controller.py | 6 ++++++ services/docker-compose-capif.yml | 2 ++ services/nginx/Dockerfile | 2 +- services/nginx/nginx.conf | 16 ++++++++++++++++ 4 files changed, 25 insertions(+), 1 deletion(-) diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/controllers/default_controller.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/controllers/default_controller.py index 695b3ae2..54c6a8ac 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/controllers/default_controller.py +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/controllers/default_controller.py @@ -84,6 +84,12 @@ def apf_id_service_apis_post(apf_id, body): # noqa: E501 """ current_app.logger.info("Publishing service") + protocol= request.headers.get('X-TLS-Protocol', 'N/A') + current_app.logger.info(f"TLS Protocol: {protocol}") + + session_id = request.headers.get('X-TLS-Session-Info', 'N/A') + current_app.logger.info(f"TLS Session ID: {session_id}") + if 'supportedFeatures' not in body: return bad_request_error( detail="supportedFeatures not present in request", diff --git a/services/docker-compose-capif.yml b/services/docker-compose-capif.yml index 037d5f35..d8835f8e 100644 --- a/services/docker-compose-capif.yml +++ b/services/docker-compose-capif.yml @@ -289,9 +289,11 @@ services: - VAULT_ACCESS_TOKEN=dev-only-token - VAULT_PORT=8200 - LOG_LEVEL=${LOG_LEVEL} + - SSLKEYLOGFILE=/var/log/nginx/sslkey.log hostname: ${CAPIF_HOSTNAME} volumes: - ./nginx/certs:/etc/nginx/certs + - ./sslkeylogs:/var/log/nginx extra_hosts: - host.docker.internal:host-gateway - vault:host-gateway diff --git a/services/nginx/Dockerfile b/services/nginx/Dockerfile index c87732c5..004ae2e8 100644 --- a/services/nginx/Dockerfile +++ b/services/nginx/Dockerfile @@ -1,4 +1,4 @@ -FROM labs.etsi.org:5050/ocf/capif/nginx:1.27.1 +FROM nginx:latest RUN apt-get update && apt-get install -y jq && apt-get clean RUN apt-get install -y openssl RUN apt-get install -y curl diff --git a/services/nginx/nginx.conf b/services/nginx/nginx.conf index f51e177f..db5ce7b2 100644 --- a/services/nginx/nginx.conf +++ b/services/nginx/nginx.conf @@ -7,6 +7,7 @@ events { worker_connections 1024; } + http { map $ssl_client_s_dn $ssl_client_s_dn_cn { default ""; @@ -50,6 +51,11 @@ http { "~*.*:.*:ccf" '{"status":401, "title":"Unauthorized" ,"detail":"User not authorized", "cause":"Certificate not authorized"}'; } + map $ssl_protocol $tls_session_info { + "TLSv1.2" $ssl_session_id; # Para TLS 1.2, usa $ssl_session_id + "TLSv1.3" "TLS_Ticket"; # Para TLS 1.3, usa un marcador (el equivalente sería un ticket de sesión) + } + server { listen 8080; @@ -71,6 +77,10 @@ http { ssl_verify_client optional; ssl_verify_depth 2; + ssl_session_cache shared:SSL:10m; + ssl_session_timeout 10m; + ssl_session_tickets on; + location / { proxy_pass $scheme://$http_host/api-invoker-management/v1/ui/; } @@ -101,6 +111,7 @@ http { add_header Content-Type 'application/problem+json'; return 401 $discover_error_message; } + proxy_set_header X-SSL-Client-Cert $ssl_client_cert; proxy_pass http://service-apis:8080; } @@ -113,6 +124,11 @@ http { add_header Content-Type 'application/problem+json'; return 401 $publish_error_message; } + + proxy_set_header X-TLS-Protocol $ssl_protocol; + proxy_set_header X-TLS-Cipher $ssl_cipher; + proxy_set_header X-TLS-Session-Info $tls_session_info; + proxy_set_header X-SSL-Client-Cert $ssl_client_cert; proxy_pass http://published-apis:8080; } -- GitLab From fbc616b1d663285c40a2b36c37ba2ac2f57211c4 Mon Sep 17 00:00:00 2001 From: Pelayo Torres Date: Fri, 28 Feb 2025 11:47:22 +0100 Subject: [PATCH 2/3] PSK Tests --- .../controllers/default_controller.py | 6 -- .../controllers/default_controller.py | 1 - .../capif_security/core/servicesecurity.py | 62 +++++++++++++- services/docker-compose-capif.yml | 2 - services/nginx/Dockerfile | 84 +++++++++++++++++-- services/nginx/nginx-sslkeylog | 1 + services/nginx/nginx.conf | 19 ++--- services/register/config.yaml.bak | 6 ++ 8 files changed, 148 insertions(+), 33 deletions(-) create mode 160000 services/nginx/nginx-sslkeylog create mode 100644 services/register/config.yaml.bak diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/controllers/default_controller.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/controllers/default_controller.py index 54c6a8ac..695b3ae2 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/controllers/default_controller.py +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/controllers/default_controller.py @@ -84,12 +84,6 @@ def apf_id_service_apis_post(apf_id, body): # noqa: E501 """ current_app.logger.info("Publishing service") - protocol= request.headers.get('X-TLS-Protocol', 'N/A') - current_app.logger.info(f"TLS Protocol: {protocol}") - - session_id = request.headers.get('X-TLS-Session-Info', 'N/A') - current_app.logger.info(f"TLS Session ID: {session_id}") - if 'supportedFeatures' not in body: return bad_request_error( detail="supportedFeatures not present in request", diff --git a/services/TS29222_CAPIF_Security_API/capif_security/controllers/default_controller.py b/services/TS29222_CAPIF_Security_API/capif_security/controllers/default_controller.py index 3609bd8f..c3dc34b4 100644 --- a/services/TS29222_CAPIF_Security_API/capif_security/controllers/default_controller.py +++ b/services/TS29222_CAPIF_Security_API/capif_security/controllers/default_controller.py @@ -170,7 +170,6 @@ def trusted_invokers_api_invoker_id_put(api_invoker_id, body): # noqa: E501 :rtype: Union[ServiceSecurity, Tuple[ServiceSecurity, int], Tuple[ServiceSecurity, int, Dict[str, str]] """ - current_app.logger.info("Creating security context") if request.is_json: body = ServiceSecurity.from_dict(request.get_json()) # noqa: E501 diff --git a/services/TS29222_CAPIF_Security_API/capif_security/core/servicesecurity.py b/services/TS29222_CAPIF_Security_API/capif_security/core/servicesecurity.py index 916b2861..884074ab 100644 --- a/services/TS29222_CAPIF_Security_API/capif_security/core/servicesecurity.py +++ b/services/TS29222_CAPIF_Security_API/capif_security/core/servicesecurity.py @@ -5,7 +5,7 @@ from datetime import datetime, timedelta import rfc3987 from bson import json_util -from flask import current_app +from flask import current_app, request from flask_jwt_extended import create_access_token from pymongo import ReturnDocument @@ -18,6 +18,10 @@ from ..models.access_token_err import AccessTokenErr from ..models.access_token_rsp import AccessTokenRsp from ..util import dict_to_camel_case, clean_empty, serialize_clean_camel_case +import hmac +import hashlib +import unicodedata + publish_ops = Publisher() security_context_not_found_detail = "Security context not found" @@ -26,6 +30,26 @@ api_invoker_no_context_cause = "API Invoker has no security context" class SecurityOperations(Resource): + def __derive_psk(self, master_key, session_id, interface_info): + + p0_string = unicodedata.normalize("NFKC", interface_info).encode("utf-8") + p1_string = unicodedata.normalize("NFKC", session_id).encode("utf-8") + + # Convert to octet format (0xFF) + p0_octet_string = ' '.join(f'0x{byte:02X}' for byte in p0_string) + p1_octet_string = ' '.join(f'0x{byte:02X}' for byte in p1_string) + + # Convert number of bytes to 16-bit big-endian + l0 = ' '.join(f'0x{byte:02X}' for byte in len(p0_octet_string).to_bytes(2, 'big')) + l1 = ' '.join(f'0x{byte:02X}' for byte in len(p1_octet_string).to_bytes(2, 'big')) + + # Create S string using FC (0x7A) and the octet strings with their lengths + S = "0x7A" + ' ' + p0_octet_string + ' ' + l0 + ' ' + p1_octet_string + ' ' + l1 + + psk = hmac.new(master_key.encode("utf-8"), S.encode("utf-8"), hashlib.sha256).digest() + + return psk + def __check_invoker(self, api_invoker_id): invokers_col = self.db.get_col_by_name(self.db.capif_invokers) @@ -132,6 +156,14 @@ class SecurityOperations(Resource): def create_servicesecurity(self, api_invoker_id, service_security): mycol = self.db.get_col_by_name(self.db.security_info) + + current_app.logger.info(request.headers.get('X-TLS-Protocol', 'N/A')) + current_app.logger.info("Creating security context") + sesionId = request.headers.get('X-TLS-Session-ID', 'N/A') + current_app.logger.info(f"TLS Session ID: {sesionId}") + + Mkey = request.headers.get('X-TLS-MKey', 'N/A') + current_app.logger.info(f"TLS MKey: {Mkey}") try: @@ -147,18 +179,29 @@ class SecurityOperations(Resource): services_security_object = mycol.find_one( {"api_invoker_id": api_invoker_id}) + current_app.logger.debug("HERE") + if services_security_object is not None: current_app.logger.error( "Already security context defined with same api invoker id") return forbidden_error(detail="Security method already defined", cause="Identical AEF Profile IDs") - + + current_app.logger.debug(service_security.security_info) for service_instance in service_security.security_info: + current_app.logger.debug(service_instance.interface_details) if service_instance.interface_details is not None: security_methods = service_instance.interface_details.security_methods pref_security_methods = service_instance.pref_security_methods valid_security_method = set( security_methods) & set(pref_security_methods) + current_app.logger.debug(service_instance.interface_details) + + interface_info = ( + getattr(service_instance.interface_details, 'ipv4_addr', None) or + getattr(service_instance.interface_details, 'ipv6_addr', None) or + getattr(service_instance.interface_details, 'fqdn', None) + ) else: capif_service_col = self.db.get_col_by_name( @@ -182,8 +225,9 @@ class SecurityOperations(Resource): "Not found comptaible security method with pref security method") return bad_request_error(detail="Not found compatible security method with pref security method", cause="Error pref security method", invalid_params=[{"param": "prefSecurityMethods", "reason": "pref security method not compatible with security method available"}]) - service_instance.sel_security_method = list( - valid_security_method)[0] + service_instance.sel_security_method = "PSK" + + # Send service instance to ACL current_app.logger.debug("Sending message to create ACL") publish_ops.publish_message("acls-messages", "create-acl:"+str( @@ -193,6 +237,16 @@ class SecurityOperations(Resource): rec = dict() rec['api_invoker_id'] = api_invoker_id + + if service_instance.sel_security_method == "PSK": + current_app.logger.info("Deriving PSK") + sesionId = request.headers.get('X-TLS-Session-ID', 'N/A') + Mkey = request.headers.get('X-TLS-MKey', 'N/A') + + invoker_psk = self.__derive_psk(Mkey, sesionId, interface_info) + current_app.logger.info(f"Derived PSK: {invoker_psk.hex()}") + rec['invoker_psk'] = invoker_psk + rec.update(service_security.to_dict()) mycol.insert_one(rec) diff --git a/services/docker-compose-capif.yml b/services/docker-compose-capif.yml index d8835f8e..037d5f35 100644 --- a/services/docker-compose-capif.yml +++ b/services/docker-compose-capif.yml @@ -289,11 +289,9 @@ services: - VAULT_ACCESS_TOKEN=dev-only-token - VAULT_PORT=8200 - LOG_LEVEL=${LOG_LEVEL} - - SSLKEYLOGFILE=/var/log/nginx/sslkey.log hostname: ${CAPIF_HOSTNAME} volumes: - ./nginx/certs:/etc/nginx/certs - - ./sslkeylogs:/var/log/nginx extra_hosts: - host.docker.internal:host-gateway - vault:host-gateway diff --git a/services/nginx/Dockerfile b/services/nginx/Dockerfile index 004ae2e8..b4dfd070 100644 --- a/services/nginx/Dockerfile +++ b/services/nginx/Dockerfile @@ -1,16 +1,86 @@ -FROM nginx:latest -RUN apt-get update && apt-get install -y jq && apt-get clean -RUN apt-get install -y openssl -RUN apt-get install -y curl -RUN apt-get -y install redis +FROM labs.etsi.org:5050/ocf/capif/nginx:1.27.1 +# 1) Instalar dependencias de compilación +RUN apt-get update && apt-get install -y \ + build-essential \ + libpcre3-dev \ + libssl-dev \ + zlib1g-dev \ + curl \ + patch \ + jq \ + openssl \ + curl \ + redis \ + && apt-get clean -RUN mkdir -p /etc/nginx/certs +# 2) Descargar fuentes +ARG NGINX_VERSION=1.27.1 +RUN curl -fSL https://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz \ + -o /tmp/nginx.tar.gz \ + && tar -xzf /tmp/nginx.tar.gz -C /tmp \ + && rm /tmp/nginx.tar.gz + +# 3) Copiar parche y módulo +COPY ./nginx-sslkeylog /tmp/nginx-sslkeylog + +WORKDIR /tmp/nginx-${NGINX_VERSION} + +RUN patch -Np1 -i /tmp/nginx-sslkeylog/nginx-patches/1.27.1.patch +# 4) Compilar e instalar +RUN ./configure \ +--prefix=/etc/nginx \ +--sbin-path=/usr/sbin/nginx \ +--modules-path=/usr/lib/nginx/modules \ +--conf-path=/etc/nginx/nginx.conf \ +--error-log-path=/var/log/nginx/error.log \ +--http-log-path=/var/log/nginx/access.log \ +--pid-path=/var/run/nginx.pid \ +--lock-path=/var/run/nginx.lock \ +--http-client-body-temp-path=/var/cache/nginx/client_temp \ +--http-proxy-temp-path=/var/cache/nginx/proxy_temp \ +--http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp \ +--http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp \ +--http-scgi-temp-path=/var/cache/nginx/scgi_temp \ +--user=nginx \ +--group=nginx \ +--with-compat \ +--with-file-aio \ +--with-threads \ +--with-http_addition_module \ +--with-http_auth_request_module \ +--with-http_dav_module \ +--with-http_flv_module \ +--with-http_gunzip_module \ +--with-http_gzip_static_module \ +--with-http_mp4_module \ +--with-http_random_index_module \ +--with-http_realip_module \ +--with-http_secure_link_module \ +--with-http_slice_module \ +--with-http_ssl_module \ +--with-http_stub_status_module \ +--with-http_sub_module \ +--with-http_v2_module \ +--with-http_v3_module \ +--with-mail \ +--with-mail_ssl_module \ +--with-stream \ +--with-stream_realip_module \ +--with-stream_ssl_module \ +--with-stream_ssl_preread_module \ +--with-cc-opt='-g -O2 -ffile-prefix-map=/data/builder/debuild/nginx-1.27.1/debian/debuild-base/nginx-1.27.1=. -fstack-protector-strong -Wformat -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -fPIC' \ +--with-ld-opt='-Wl,-z,relro -Wl,-z,now -Wl,--as-needed -pie' \ +--add-module=/tmp/nginx-sslkeylog \ + && make -j$(nproc) \ + && make install + +# 5) Ajustar tu config +RUN mkdir -p /etc/nginx/certs COPY ./certs/sign_req_body_tmp.json /etc/nginx/certs/sign_req_body_tmp.json COPY ./nginx.conf /etc/nginx/nginx.conf COPY ./nginx_prepare.sh . - RUN chmod a+x nginx_prepare.sh CMD ["sh", "nginx_prepare.sh"] diff --git a/services/nginx/nginx-sslkeylog b/services/nginx/nginx-sslkeylog new file mode 160000 index 00000000..f0356898 --- /dev/null +++ b/services/nginx/nginx-sslkeylog @@ -0,0 +1 @@ +Subproject commit f0356898000b771ce6bbaa48586c85c6d72904ec diff --git a/services/nginx/nginx.conf b/services/nginx/nginx.conf index db5ce7b2..b1ca67c4 100644 --- a/services/nginx/nginx.conf +++ b/services/nginx/nginx.conf @@ -51,11 +51,6 @@ http { "~*.*:.*:ccf" '{"status":401, "title":"Unauthorized" ,"detail":"User not authorized", "cause":"Certificate not authorized"}'; } - map $ssl_protocol $tls_session_info { - "TLSv1.2" $ssl_session_id; # Para TLS 1.2, usa $ssl_session_id - "TLSv1.3" "TLS_Ticket"; # Para TLS 1.3, usa un marcador (el equivalente sería un ticket de sesión) - } - server { listen 8080; @@ -76,10 +71,8 @@ http { ssl_client_certificate /etc/nginx/certs/ca.crt; ssl_verify_client optional; ssl_verify_depth 2; - - ssl_session_cache shared:SSL:10m; - ssl_session_timeout 10m; - ssl_session_tickets on; + + ssl_session_tickets off; location / { proxy_pass $scheme://$http_host/api-invoker-management/v1/ui/; @@ -125,10 +118,6 @@ http { return 401 $publish_error_message; } - proxy_set_header X-TLS-Protocol $ssl_protocol; - proxy_set_header X-TLS-Cipher $ssl_cipher; - proxy_set_header X-TLS-Session-Info $tls_session_info; - proxy_set_header X-SSL-Client-Cert $ssl_client_cert; proxy_pass http://published-apis:8080; } @@ -158,6 +147,10 @@ http { return 401 $security_error_message; } + proxy_set_header X-TLS-Protocol $ssl_protocol; + proxy_set_header X-TLS-Session-ID $ssl_session_id; + proxy_set_header X-TLS-MKey $sslkeylog_mk; + proxy_set_header X-SSL-Client-Cert $ssl_client_cert; proxy_pass http://capif-security:8080; } diff --git a/services/register/config.yaml.bak b/services/register/config.yaml.bak new file mode 100644 index 00000000..fb61459d --- /dev/null +++ b/services/register/config.yaml.bak @@ -0,0 +1,6 @@ +mongo: {'user': 'root', 'password': 'example', 'db': 'capif_users', 'col': 'user', 'admins': 'admins', 'host': 'mongo_register', 'port': '27017'} +ca_factory: {"url": "vault", "port": "8200", "token": "dev-only-token", "verify": False} +ccf: {"url": "capifcore", "helper_remove_user": "/helper/deleteEntities/"} +register: {"register_uuid": '6ba7b810-9dad-11d1-80b4-00c04fd430c8', "refresh_expiration": 30, #days + "token_expiration": 10, #mins + "admin_users": {admin_user: "admin", admin_pass: "password123"}} -- GitLab From 6c0b8bb76723d027e245897f968bc0fdaa9f7a68 Mon Sep 17 00:00:00 2001 From: Pelayo Torres Date: Wed, 21 May 2025 10:44:16 +0200 Subject: [PATCH 3/3] nginx image --- services/docker-compose-capif.yml | 2 +- services/nginx/Dockerfile | 84 +++---------------------------- 2 files changed, 8 insertions(+), 78 deletions(-) diff --git a/services/docker-compose-capif.yml b/services/docker-compose-capif.yml index 037d5f35..a6e1fcf0 100644 --- a/services/docker-compose-capif.yml +++ b/services/docker-compose-capif.yml @@ -282,7 +282,7 @@ services: ports: - "8080:8080" - "443:443" - image: labs.etsi.org:5050/ocf/capif/nginx:v2.x.x-release + image: pelayo222/mi-nginx:1.27.1-arm64 environment: - CAPIF_HOSTNAME=${CAPIF_HOSTNAME} - VAULT_HOSTNAME=vault diff --git a/services/nginx/Dockerfile b/services/nginx/Dockerfile index b4dfd070..d34d8b94 100644 --- a/services/nginx/Dockerfile +++ b/services/nginx/Dockerfile @@ -1,86 +1,16 @@ -FROM labs.etsi.org:5050/ocf/capif/nginx:1.27.1 +FROM pelayo222/mi-nginx:1.27.1-arm64 +RUN apt-get update && apt-get install -y jq && apt-get clean +RUN apt-get install -y openssl +RUN apt-get install -y curl +RUN apt-get -y install redis -# 1) Instalar dependencias de compilación -RUN apt-get update && apt-get install -y \ - build-essential \ - libpcre3-dev \ - libssl-dev \ - zlib1g-dev \ - curl \ - patch \ - jq \ - openssl \ - curl \ - redis \ - && apt-get clean -# 2) Descargar fuentes -ARG NGINX_VERSION=1.27.1 -RUN curl -fSL https://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz \ - -o /tmp/nginx.tar.gz \ - && tar -xzf /tmp/nginx.tar.gz -C /tmp \ - && rm /tmp/nginx.tar.gz - -# 3) Copiar parche y módulo -COPY ./nginx-sslkeylog /tmp/nginx-sslkeylog - -WORKDIR /tmp/nginx-${NGINX_VERSION} - -RUN patch -Np1 -i /tmp/nginx-sslkeylog/nginx-patches/1.27.1.patch - -# 4) Compilar e instalar -RUN ./configure \ ---prefix=/etc/nginx \ ---sbin-path=/usr/sbin/nginx \ ---modules-path=/usr/lib/nginx/modules \ ---conf-path=/etc/nginx/nginx.conf \ ---error-log-path=/var/log/nginx/error.log \ ---http-log-path=/var/log/nginx/access.log \ ---pid-path=/var/run/nginx.pid \ ---lock-path=/var/run/nginx.lock \ ---http-client-body-temp-path=/var/cache/nginx/client_temp \ ---http-proxy-temp-path=/var/cache/nginx/proxy_temp \ ---http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp \ ---http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp \ ---http-scgi-temp-path=/var/cache/nginx/scgi_temp \ ---user=nginx \ ---group=nginx \ ---with-compat \ ---with-file-aio \ ---with-threads \ ---with-http_addition_module \ ---with-http_auth_request_module \ ---with-http_dav_module \ ---with-http_flv_module \ ---with-http_gunzip_module \ ---with-http_gzip_static_module \ ---with-http_mp4_module \ ---with-http_random_index_module \ ---with-http_realip_module \ ---with-http_secure_link_module \ ---with-http_slice_module \ ---with-http_ssl_module \ ---with-http_stub_status_module \ ---with-http_sub_module \ ---with-http_v2_module \ ---with-http_v3_module \ ---with-mail \ ---with-mail_ssl_module \ ---with-stream \ ---with-stream_realip_module \ ---with-stream_ssl_module \ ---with-stream_ssl_preread_module \ ---with-cc-opt='-g -O2 -ffile-prefix-map=/data/builder/debuild/nginx-1.27.1/debian/debuild-base/nginx-1.27.1=. -fstack-protector-strong -Wformat -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -fPIC' \ ---with-ld-opt='-Wl,-z,relro -Wl,-z,now -Wl,--as-needed -pie' \ ---add-module=/tmp/nginx-sslkeylog \ - && make -j$(nproc) \ - && make install - -# 5) Ajustar tu config RUN mkdir -p /etc/nginx/certs + COPY ./certs/sign_req_body_tmp.json /etc/nginx/certs/sign_req_body_tmp.json COPY ./nginx.conf /etc/nginx/nginx.conf COPY ./nginx_prepare.sh . + RUN chmod a+x nginx_prepare.sh CMD ["sh", "nginx_prepare.sh"] -- GitLab