SSH Programming Guide for NetBurner Devices
Overview
The Secure Shell Protocol (SSH) is a cryptographic network protocol for secure remote access and command execution over unsecured networks. First introduced in 1995, SSH remains the industry standard for secure remote administration.
NetBurner SSH Implementation
NetBurner has supported SSH since NNDK 2.0. As of NNDK 3.3.6, we've migrated from Dropbear to wolfSSH, providing significant improvements:
┌──────────────────────────────────────────────────────────┐
│ NetBurner SSH Evolution │
├──────────────────────────────────────────────────────────┤
│ │
│ NNDK 2.0 - 3.3.5 NNDK 3.3.6+ │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ Dropbear │ ──> │ wolfSSH │ │
│ │ SSH │ │ │ │
│ └─────────────┘ └─────────────┘ │
│ │
│ Features: Enhanced Features: │
│ - Server only - Server & Client support │
│ - Limited ciphers - Modern cipher suites │
│ - Separate crypto lib - Shared wolfCrypt library │
│ - Smaller code footprint │
│ - Auto-generated keys │
└──────────────────────────────────────────────────────────┘
Key Benefits of wolfSSH
Enhanced Security**
- Updated cipher suites and algorithms
- Support for modern cryptographic standards
Regular security updates
Client Support**
- SSH client functionality now available
- Connect to remote SSH servers from NetBurner devices
Automated remote management capabilities
Code Efficiency**
- Shared wolfCrypt library with SSL/TLS
- Reduced memory footprint when using both protocols
Optimized for embedded systems
Simplified Key Management**
- Automatic key generation on device
- Multiple key format support
- Flexible key installation methods
What's New in NNDK 3.3.6+
Major Changes Summary
┌─────────────────────────────────────────────────────────────┐
│ wolfSSH Migration │
├─────────────────────────────────────────────────────────────┤
│ │
│ [ADDED] SSH Client Support │
│ [ADDED] Onboard Key Generation │
│ [ADDED] Enhanced Authentication (keys + passwords) │
│ [IMPROVED] Modern Cipher Suites │
│ [IMPROVED] Shared Crypto Library (wolfCrypt) │
│ [CHANGED] Task Management (CryptoServer) │
│ [REMOVED] Dropbear-specific Functions │
│ │
└─────────────────────────────────────────────────────────────┘
The user authorization manager class allows application developers the ability to manage user authori...
Definition UserAuthManager.h:116
Architecture Change
Previous Architecture (NNDK 3.3.5 and earlier):**
┌─────────────┐ ┌─────────────┐
│ SSH Session │ │ SSH Session │
│ (Task) │ │ (Task) │
└─────────────┘ └─────────────┘
| |
v v
┌─────────────────────────────────┐
│ Dropbear Library │
└─────────────────────────────────┘
New Architecture (NNDK 3.3.6+):**
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ SSH Session │ │ SSH Session │ │ SSL Session │
└─────────────┘ └─────────────┘ └─────────────┘
| | |
v v v
┌───────────────────────────────────────────────────────┐
│ CryptoServer Task │
├───────────────────────────────────────────────────────┤
│ │
│ ┌──────────┐ ┌──────────┐ │
│ │ wolfSSH │ <──────> │ wolfCrypt│ │
│ └──────────┘ └──────────┘ │
│ ^ │
│ | │
│ ┌──────────┐ │
│ │ wolfSSL │ │
│ └──────────┘ │
└───────────────────────────────────────────────────────┘
#define SECURITY_TASK_PRIO
Definition constants.h:142
Key Architectural Improvements:**
- Unified task management through CryptoServer
- Shared cryptographic primitives (wolfCrypt)
- Reduced resource overhead
- Consistent security across protocols
Key Types and Formats
Supported Key Types
The SSH library supports both ECC (Elliptic Curve Cryptography) and RSA keys.
┌───────────────────────────────────────────────────────────┐
│ Supported SSH Key Types │
├───────────────────────────────────────────────────────────┤
│ │
│ ECC (Elliptic Curve) - RECOMMENDED │
│ ┌─────────────────────────────────────────────────┐ │
│ │ Key Sizes: 160 to 512 bits │ │
│ │ Advantages: - Smaller key size │ │
│ │ - Faster operations │ │
│ │ - Lower memory usage │ │
│ │ Use Case: Embedded systems, IoT devices │ │
│ └─────────────────────────────────────────────────┘ │
│ │
│ RSA (Rivest-Shamir-Adleman) │
│ ┌─────────────────────────────────────────────────┐ │
│ │ Default Size: 2048 bits │ │
│ │ Optional: 4096 bits (define ENABLE_RSA_4K) │ │
│ │ Advantages: - Widely compatible │ │
│ │ - Well-established │ │
│ │ Use Case: Legacy system compatibility │ │
│ └─────────────────────────────────────────────────┘ │
│ │
└───────────────────────────────────────────────────────────┘
Enabling RSA 4096-bit Keys
To enable 4096-bit RSA key support:
- Open
<nndk_install>\nbrtos\include\predef.h
- Add the following definition:
- Rebuild your application
Supported Key Formats
Both key types support two formats:
┌─────────────────────────────────────────────────────┐
│ SSH Key Format Support │
├─────────────────────────────────────────────────────┤
│ │
│ PEM Format (Privacy-Enhanced Mail) │
│ ┌───────────────────────────────────────────┐ │
│ │ -----BEGIN RSA PRIVATE KEY----- │ │
│ │ Base64 encoded key data... │ │
│ │ -----END RSA PRIVATE KEY----- │ │
│ │ │ │
│ │ - Human readable (text) │ │
│ │ - Base64 encoding │ │
│ │ - Easier to copy/paste │ │
│ │ - Larger file size │ │
│ └───────────────────────────────────────────┘ │
│ │
│ ASN.1/DER Format (Distinguished Encoding Rules) │
│ ┌───────────────────────────────────────────┐ │
│ │ Binary encoded key data │ │
│ │ (not human readable) │ │
│ │ │ │
│ │ - Binary format │ │
│ │ - Smaller file size │ │
│ │ - Faster parsing │ │
│ │ - More efficient for embedded systems │ │
│ └───────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────┘
Migration Guide
Project Configuration
Step 1: Add Required Include Paths**
When building SSH applications in NBEclipse, add the following include paths:
${NNDK_ROOT}/libraries/include/ssh
${NNDK_ROOT}/libraries/include/crypto
Step 2: Configure in NBEclipse**
Project Configuration Flow:
1. Right-click project
|
v
2. Select "Properties"
|
v
3. Navigate to "C/C++ Build" > "Settings"
|
v
4. Select "Includes" under:
- GNU C Compiler
- GNU C++ Compiler
|
v
5. Click green "+" icon
|
v
6. Add paths:
${NNDK_ROOT}/libraries/include/ssh
${NNDK_ROOT}/libraries/include/crypto
|
v
7. Click "Apply"
|
v
8. Clean and rebuild project
Removed Functions
The following Dropbear-specific functions have been removed:
┌─────────────────────────────────────────────────────────────┐
│ Removed Functions │
├─────────────────────────────────────────────────────────────┤
│ │
│ SshConvertDecodedOpenSSLKey() │
│ ├─ Purpose: Converted PEM to Dropbear format │
│ ├─ Reason: No longer needed - native PEM/ASN.1 support │
│ └─ Action: Remove from code │
│ │
│ SshSetchansessionrequest() │
│ ├─ Purpose: Set callback for channel requests │
│ ├─ Reason: Handled internally by wolfSSH │
│ └─ Action: Remove callback - automatic handling │
│ │
│ SshSetTaskPriority() │
│ ├─ Purpose: Set SSH task priority │
│ ├─ Reason: Managed by CryptoServer task │
│ │
└─────────────────────────────────────────────────────────────┘
Updated Functions
Replace deprecated functions with their enhanced versions:
Authentication Function Pointer
Old (Deprecated):**
void SshSetUserAuthenticate(sshUserAuthenticateFn sshUserAuthenticateFnPtr)
[DEPRECATED] Sets the user defined server authentication function. Please consider sshUserAuthenticat...
int(* sshUserAuthenticateFn)(const char *usernamePtr, const char *passwordPtr)
[DEPRECATED] User provided SSH username and password authenticate routine for a server....
Definition NbWolfSsh.h:107
sshUserAuthenticateFn SshGetUserAuthenticate(void)
[DEPRECATED] Gets the user defined server authentication function. Please consider SshGetUserAuthenti...
New (Recommended):**
const char* authValue,
void SshSetUserAuthenticateWithType(sshUserAuthenticateWithTypeFn sshUserAuthenticateFnPtr)
Sets the user defined server authentication function.
int(* sshUserAuthenticateWithTypeFn)(const char *usernamePtr, const char *authValPtr, AuthType authType)
User provided SSH user authenticate routine for a server.
Definition NbWolfSsh.h:119
sshUserAuthenticateWithTypeFn SshGetUserAuthenticateWithType(void)
Gets the user defined server authentication function..
AuthType
The types of authorization requests that are managed. These just indicate what the has value is,...
Definition UserAuthManager.h:44
Migration Example:**
int MyAuthCallback(const char* username, const char* password) {
if (strcmp(username, "admin") == 0 && strcmp(password, "secret") == 0) {
return 1;
}
return 0;
}
void setup() {
}
int MyAuthCallbackWithType(const char* username,
const char* authValue,
if (authType == AUTH_TYPE_PASSWORD) {
if (strcmp(username, "admin") == 0 &&
strcmp(authValue, "secret") == 0) {
return 1;
}
}
else if (authType == AUTH_TYPE_KEY) {
if (ValidatePublicKey(username, authValue)) {
return 1;
}
}
return 0;
}
void setup() {
}
Authentication Type Enum:**
typedef enum {
AUTH_TYPE_PASSWORD,
AUTH_TYPE_KEY,
AUTH_TYPE_UNKNOWN
Key Management
Key Installation Methods
SSH keys can be installed using three methods, checked in the following priority order:
Key Selection Priority (Checked in Order):
1. Runtime Callback
┌─────────────────────────────┐
│ Returns key dynamically │
└─────────────────────────────┘
|
| Not set?
v
2. Compiled-In Key
┌─────────────────────────────┐
│ Weak function override │
└─────────────────────────────┘
|
| Not overridden?
v
3. Auto-Generated Key
┌─────────────────────────────┐
│ Onboard generated key │
│ Same as SSL/TLS key │
└─────────────────────────────┘
void SshSetUserGetKey(sshUserGetKeyFn sshUserGetKeyFnPtr)
Sets the user defined callback method to provide the server key.
const char * GetPrivateKeyPEM()
Function that returns a pointer to the compiled in server key.
Definition SSH/SecureSerToEthFactoryApp/src/ssluser.cpp:101
Method 1: Runtime Callback (Highest Priority)
Use this method for dynamic key selection or key rotation.
#include <ssh.h>
typedef int (*SshUserGetKeyFn)(const char** keyData,
int* keyLen,
int* keyFormat);
int GetSshKey(const char** keyData, int* keyLen, int* keyFormat) {
static const char myKey[] =
"-----BEGIN EC PRIVATE KEY-----\n"
"MHcCAQEEIIGN...key data...zqk\n"
"-----END EC PRIVATE KEY-----\n";
*keyData = myKey;
*keyLen = sizeof(myKey) - 1;
*keyFormat = SSH_KEY_FORMAT_PEM;
return 1;
}
void UserMain(void* pd) {
StartSsh();
}
#define TICKS_PER_SECOND
System clock ticks per second.
Definition constants.h:49
void init()
System initialization. Ideally called at the beginning of all applications, since the easiest Recover...
Key Format Constants:**
#define SSH_KEY_FORMAT_PEM 0
#define SSH_KEY_FORMAT_DER 1
Method 2: Compiled-In Key (Medium Priority)
Override the weak function to provide a compiled-in key.
#include <ssh.h>
extern const unsigned char myPrivateKey[];
extern const int myPrivateKeyLen;
return (const char*)myPrivateKey;
}
extern const unsigned char myPrivateKey[] = {
0x2d, 0x2d, 0x2d, 0x2d, 0x2d,
};
extern const int myPrivateKeyLen = sizeof(myPrivateKey);
Generating Compiled Key File:**
# Convert PEM key to C array using compfile
compfile ssh_key.pem myPrivateKey myPrivateKeyLen ssh_key.cpp
# Add ssh_key.cpp to your project's makefile
CPP_SRC += src/ssh_key.cpp
Method 3: Auto-Generated Key (Lowest Priority)
Enable automatic key generation on the device.
void UserMain(void* pd) {
StartSsh();
printf("SSH server started with auto-generated key\n");
}
Enable Auto-Regeneration:**
To automatically regenerate expired keys, add to predef.h:
#define ENABLE_AUTOCERT_REGEN
#define AUTO_CERT_GEN_CHECK (60 * 20)
Key Generation Details:**
User Authentication
UserAuthManager Class
NetBurner provides the UserAuthManager class to simplify user credential management.
┌──────────────────────────────────────────────────────┐
├──────────────────────────────────────────────────────┤
│ │
│ Application Code │
│ ┌────────────────────────────────────────────┐ │
│ │ Add/Remove/Verify Users │ │
│ └──────────────────┬─────────────────────────┘ │
│ | │
│ v │
│ ┌──────────────────────────────────────────────┐ │
│ │ ┌────────────────────────────────────┐ │ │
│ │ │ - Hashed password storage │ │ │
│ │ │ - Public key storage │ │ │
│ │ │ - Authentication verification │ │ │
│ │ └────────────────────────────────────┘ │ │
│ └──────────────────┬───────────────────────────┘ │
│ | │
│ v │
│ ┌──────────────────────────────────────────────┐ │
│ │ Storage Layer (via callbacks) │ │
│ │ ┌────────────────────────────────────┐ │ │
│ │ └────────────────────────────────────┘ │ │
│ │ │ │
│ │ Choose storage: │ │
│ │ - User Param space │ │
│ │ - SD card / Flash │ │
│ │ - External EEPROM │ │
│ │ - Database │ │
│ └──────────────────────────────────────────────┘ │
│ │
└──────────────────────────────────────────────────────┘
int(* LoadAuthRecordsFn)(UserAuthRecord *authRec)
User provided function for loading user authorization records. This allows the users to dictate where...
Definition UserAuthManager.h:107
int(* SaveAuthRecordsFn)(const UserAuthRecord *authRec)
User provided function for saving user authorization records. This allows the users to dictate where ...
Definition UserAuthManager.h:96
Key Features
Security Features:**
Basic Usage
#include <UserAuthManager.h>
void InitializeAuth() {
authManager.SetLoadCallback(LoadAuthRecords);
authManager.SetSaveCallback(SaveAuthRecords);
authManager.Load();
}
void AddPasswordUser(const char* username, const char* password) {
if (authManager.AddUser(username, password, AUTH_TYPE_PASSWORD)) {
printf("User %s added successfully\n", username);
authManager.Save();
} else {
printf("Failed to add user %s\n", username);
}
}
void AddKeyUser(const char* username, const char* publicKey) {
if (authManager.AddUser(username, publicKey, AUTH_TYPE_KEY)) {
printf("User %s added with key authentication\n", username);
authManager.Save();
} else {
printf("Failed to add user %s\n", username);
}
}
int AuthenticateUser(const char* username,
const char* authValue,
return authManager.Authenticate(username, authValue, authType);
}
void RemoveUser(const char* username) {
if (authManager.RemoveUser(username)) {
printf("User %s removed\n", username);
authManager.Save();
}
}
Storage Callbacks
Implement custom storage using callbacks:
#include <UserAuthManager.h>
#include <nbjson.h>
#include <UserParams.h>
const char* jsonData = GetUserParam("SSH_USERS");
if (!jsonData) return 0;
if (ParseJsonData(jsonData, jsonSet)) {
for (int i = 0; i < jsonSet.m_numDataElements; i++) {
const char* username = jsonSet.FindName("username", i);
const char* authData = jsonSet.FindName("auth", i);
const char* typeStr = jsonSet.FindName("type", i);
AuthType type = (strcmp(typeStr,
"key") == 0) ?
AUTH_TYPE_KEY : AUTH_TYPE_PASSWORD;
manager.AddUserHashed(username, authData, type);
}
return 1;
}
return 0;
}
char jsonBuffer[4096];
int offset = 0;
offset += sprintf(jsonBuffer + offset, "{\"users\":[");
offset += sprintf(jsonBuffer + offset, "]}");
return SetUserParam("SSH_USERS", jsonBuffer);
}
void InitializeAuthStorage() {
authManager.SetLoadCallback(LoadAuthRecords);
authManager.SetSaveCallback(SaveAuthRecords);
authManager.Load();
}
A class to create, read, and modify a JSON object.
Definition json_lexer.h:535
Integration with SSH Authentication
#include <ssh.h>
#include <UserAuthManager.h>
int SshAuthCallback(const char* username,
const char* authValue,
int result = g_authManager.Authenticate(username, authValue, authType);
if (result) {
printf("SSH: User '%s' authenticated successfully\n", username);
} else {
printf("SSH: Authentication failed for user '%s'\n", username);
}
return result;
}
void UserMain(void* pd) {
g_authManager.SetLoadCallback(LoadAuthRecords);
g_authManager.SetSaveCallback(SaveAuthRecords);
g_authManager.Load();
StartSsh();
printf("SSH server running with UserAuthManager\n");
}
Security Best Practices
┌───────────────────────────────────────────────────────┐
├───────────────────────────────────────────────────────┤
│ │
│ [HASH] Passwords hashed before storage │
│ - Never store plain-text passwords │
│ - Secure hash algorithms used │
│ │
│ [SAFE] Constant-time comparison │
│ - Prevents timing attacks │
│ - Secure credential verification │
│ │
│ [FLEX] Pluggable storage │
│ - Choose your storage backend │
│ - Encrypt at rest if needed │
│ - Control access permissions │
│ │
│ [KEYS] Public key support │
│ - Store SSH public keys │
│ - Key-based authentication │
│ - More secure than passwords │
│ │
└───────────────────────────────────────────────────────┘
Recommendations:**
- Always hash passwords before storage
- Use secure storage (encrypted if possible)
- Implement proper access controls
- Prefer key-based authentication
- Regularly audit user accounts
- Implement account lockout policies
- Log authentication attempts
Configuration
SSH Server Configuration
Basic SSH server setup:
#include <init.h>
#include <ssh.h>
const char* AppName = "SSH Server Example";
void UserMain(void* pd) {
if (StartSsh() == 0) {
printf("SSH server started successfully\n");
} else {
printf("Failed to start SSH server\n");
}
while(1) {
}
}
bool WaitForActiveNetwork(uint32_t ticks_to_wait=120 *TICKS_PER_SECOND, int interface=-1)
Wait for an active network connection on at least one interface.
SSH Client Configuration
Connect to remote SSH servers:
#include <ssh.h>
void ConnectToRemoteServer() {
SshClientConfig config;
config.hostname = "remote.server.com";
config.port = 22;
config.username = "admin";
config.password = "secret";
SSH_CLIENT* client = SshClientConnect(&config);
if (client) {
printf("Connected to remote SSH server\n");
char response[1024];
int result = SshClientExecute(client, "ls -la",
response, sizeof(response));
if (result > 0) {
printf("Command output:\n%s\n", response);
}
SshClientDisconnect(client);
} else {
printf("Failed to connect to SSH server\n");
}
}
Advanced Configuration
#include <ssh.h>
void ConfigureSshAdvanced() {
SshSetPort(2222);
SshSetTimeout(30);
SshSetMaxConnections(5);
SshEnablePasswordAuth(true);
SshEnableKeyAuth(true);
SshSetBanner("Welcome to NetBurner SSH Server\n");
StartSsh();
}
Configuration Constants
Common SSH configuration constants:
#define SSH_DEFAULT_PORT 22
#define SSH_DEFAULT_TIMEOUT 60
#define SSH_DEFAULT_MAX_CONNECTIONS 10
#define SSH_DEFAULT_KEY_SIZE 2048
#define SECURITY_TASK_PRIO 45
#define SSH_MAX_USERNAME_LEN 32
#define SSH_MAX_PASSWORD_LEN 64
#define SSH_MAX_COMMAND_LEN 1024
#define SSH_MAX_RESPONSE_LEN 4096
Examples and Best Practices
Example 1: Basic SSH Server
#include <init.h>
#include <ssh.h>
#include <UserAuthManager.h>
const char* AppName = "Basic SSH Server";
int AuthUser(
const char* username,
const char* authValue,
AuthType type) {
return authManager.Authenticate(username, authValue, type);
}
void InitDefaultUsers() {
authManager.AddUser("admin", "admin123", AUTH_TYPE_PASSWORD);
printf("Default user 'admin' created\n");
}
void UserMain(void* pd) {
printf("Starting %s\n", AppName);
InitDefaultUsers();
StartSsh();
printf("SSH server running on port 22\n");
printf("Connect with: ssh admin@%s\n", GetIP().c_str());
while(1) {
}
}
Example 2: SSH Server with Persistent Users
#include <init.h>
#include <ssh.h>
#include <UserAuthManager.h>
#include <UserParams.h>
#include <nbjson.h>
const char* jsonData = GetUserParam("SSH_USERS");
if (!jsonData) return 0;
if (ParseJsonData(jsonData, jsonSet)) {
for (int i = 0; i < jsonSet.m_numDataElements; i++) {
const char* user = jsonSet.FindName("user", i);
const char* hash = jsonSet.FindName("hash", i);
const char* type = jsonSet.FindName("type", i);
AuthType authType = (strcmp(type,
"key") == 0) ?
AUTH_TYPE_KEY : AUTH_TYPE_PASSWORD;
mgr.AddUserHashed(user, hash, authType);
}
return 1;
}
return 0;
}
char json[2048];
return SetUserParam("SSH_USERS", json);
}
int AuthUser(
const char* username,
const char* authValue,
AuthType type) {
int result = authManager.Authenticate(username, authValue, type);
if (result) {
printf("[SSH] Login success: %s\n", username);
} else {
printf("[SSH] Login failed: %s\n", username);
}
return result;
}
void UserMain(void* pd) {
authManager.SetLoadCallback(LoadUsers);
authManager.SetSaveCallback(SaveUsers);
authManager.Load();
if (authManager.GetUserCount() == 0) {
authManager.AddUser("admin", "netburner", AUTH_TYPE_PASSWORD);
authManager.Save();
printf("Created default admin user\n");
}
StartSsh();
printf("SSH server ready - %d users loaded\n",
authManager.GetUserCount());
}
Example 3: SSH Client
#include <init.h>
#include <ssh.h>
void ExecuteRemoteCommand(const char* host, const char* command) {
SshClientConfig config;
config.hostname = host;
config.port = 22;
config.username = "admin";
config.password = "password";
SSH_CLIENT* client = SshClientConnect(&config);
if (client) {
char response[4096];
int len = SshClientExecute(client, command,
response, sizeof(response));
if (len > 0) {
printf("Response from %s:\n%s\n", host, response);
} else {
printf("Command execution failed\n");
}
SshClientDisconnect(client);
}
}
void UserMain(void* pd) {
ExecuteRemoteCommand("192.168.1.100", "uptime");
ExecuteRemoteCommand("192.168.1.101", "df -h");
}
Example 4: Custom Key Management
#include <init.h>
#include <ssh.h>
const char* productionKey =
"-----BEGIN EC PRIVATE KEY-----\n"
"MHcCAQEE...production key...\n"
"-----END EC PRIVATE KEY-----\n";
const char* developmentKey =
"-----BEGIN EC PRIVATE KEY-----\n"
"MHcCAQEE...development key...\n"
"-----END EC PRIVATE KEY-----\n";
int GetSshKey(const char** keyData, int* keyLen, int* keyFormat) {
#ifdef PRODUCTION
*keyData = productionKey;
*keyLen = strlen(productionKey);
#else
*keyData = developmentKey;
*keyLen = strlen(developmentKey);
#endif
*keyFormat = SSH_KEY_FORMAT_PEM;
return 1;
}
void UserMain(void* pd) {
StartSsh();
#ifdef PRODUCTION
printf("SSH: Using production key\n");
#else
printf("SSH: Using development key\n");
#endif
}
Best Practices
┌────────────────────────────────────────────────────────┐
│ SSH Security Best Practices │
├────────────────────────────────────────────────────────┤
│ │
│ [1] Key Management │
│ - Use ECC keys when possible (smaller, faster) │
│ - Rotate keys regularly │
│ - Never hardcode keys in source code │
│ - Store keys securely │
│ │
│ [2] Authentication │
│ - Prefer key-based over password authentication │
│ - Use strong passwords (12+ characters) │
│ - Implement account lockout after failed │
│ attempts │
│ │
│ [3] Network Security │
│ - Use non-standard ports when possible │
│ - Implement IP whitelisting/blacklisting │
│ - Set appropriate connection timeouts │
│ - Limit maximum concurrent connections │
│ │
│ [4] Monitoring │
│ - Log all authentication attempts │
│ - Monitor for suspicious activity │
│ - Track active sessions │
│ - Alert on anomalies │
│ │
│ [5] Updates │
│ - Keep NNDK updated for security patches │
│ - Review wolfSSH release notes │
│ - Test updates in development first │
│ │
└────────────────────────────────────────────────────────┘
Quick Reference
Essential Functions
Server Functions
int StartSsh(void);
int StopSsh(void);
void SshSetPort(uint16_t port);
void SshSetTimeout(uint32_t seconds);
void SshSetMaxConnections(int max);
Client Functions
SSH_CLIENT* SshClientConnect(SshClientConfig* config);
void SshClientDisconnect(SSH_CLIENT* client);
int SshClientExecute(SSH_CLIENT* client, const char* command,
char* response, int maxLen);
int SshClientUpload(SSH_CLIENT* client, const char* localPath,
const char* remotePath);
int SshClientDownload(SSH_CLIENT* client, const char* remotePath,
const char* localPath);
UserAuthManager Functions
bool AddUser(
const char* username,
const char* authValue,
AuthType type);
bool RemoveUser(const char* username);
bool UserExists(const char* username);
int GetUserCount(void);
int Authenticate(const char* username, const char* authValue,
bool Load(void);
bool Save(void);
Common Patterns
Pattern 1: Simple Server
void UserMain(void* pd) {
StartSsh();
}
Pattern 2: Server with Authentication
int AuthCallback(
const char* user,
const char* auth,
AuthType type) {
return authManager.Authenticate(user, auth, type);
}
void UserMain(void* pd) {
authManager.Load();
StartSsh();
}
Pattern 3: Client Connection
void ConnectAndExecute(const char* host, const char* cmd) {
SshClientConfig cfg = {host, 22, "admin", "password"};
SSH_CLIENT* client = SshClientConnect(&cfg);
if (client) {
char buf[1024];
SshClientExecute(client, cmd, buf, sizeof(buf));
printf("%s\n", buf);
SshClientDisconnect(client);
}
}
Troubleshooting
┌─────────────────────────────────────────────────────┐
│ Common SSH Issues & Solutions │
├─────────────────────────────────────────────────────┤
│ │
│ Connection Refused │
│ ├─ Check SSH server is started │
│ ├─ Verify port is not blocked by firewall │
│ └─ Confirm device has network connectivity │
│ │
│ Authentication Failed │
│ ├─ Verify credentials are correct │
│ ├─ Check authentication callback is registered │
│ └─ Check auth logs for details │
│ │
│ Key Not Found │
│ ├─ Verify key callback is set (if using) │
│ ├─ Ensure auto-generation is enabled │
│ └─ Review key priority order │
│ │
│ Build Errors │
│ ├─ Add required include paths: │
│ │ ${NNDK_ROOT}/libraries/include/ssh │
│ │ ${NNDK_ROOT}/libraries/include/crypto │
│ ├─ Clean and rebuild project │
│ └─ Check for deprecated function usage │
│ │
│ Memory Issues │
│ ├─ Check available heap space │
│ ├─ Limit concurrent SSH connections │
│ └─ Review cipher suite configuration │
│ │
└─────────────────────────────────────────────────────┘
Debug Logging
Enable SSH debug output:
#include <ssh.h>
void UserMain(void* pd) {
SshSetDebugLevel(SSH_DEBUG_VERBOSE);
StartSsh();
}
Migration Checklist
When migrating from NNDK 3.3.5 or earlier:
Migration Steps:
[ ] Add include paths to project:
${NNDK_ROOT}/libraries/include/ssh
${NNDK_ROOT}/libraries/include/crypto
[ ] Remove deprecated functions:
[ ] SshConvertDecodedOpenSSLKey()
[ ] SshSetchansessionrequest()
[ ] SshSetTaskPriority()
[ ] Update authentication code:
[ ] Update callback to handle
AuthType parameter
[ ] Test key management:
[ ] Verify key installation method works
[ ] Test auto-generated keys if used
[ ] Confirm key format compatibility
[ ] Validate functionality:
[ ] Test SSH server connections
[ ] Verify authentication works
[ ] Test SSH client if used
[ ] Check memory usage
[ ] Review security:
[ ] Update cipher suites if needed
[ ] Review authentication policies
[ ] Test key rotation procedures
[ ] Verify logging and monitoring
Summary
This guide has covered:
- wolfSSH migration and benefits
- Supported key types and formats
- Migration from NNDK 3.3.5 to 3.3.6+
- Key management strategies
- User authentication with UserAuthManager
- Configuration and examples
- Best practices and troubleshooting
Key Takeaways
┌──────────────────────────────────────────────────────┐
│ SSH Implementation Summary │
├──────────────────────────────────────────────────────┤
│ │
│ [MODERN] wolfSSH replaces Dropbear │
│ [CLIENT] SSH client support now available │
│ [SECURE] Enhanced ciphers and key management │
│ [AUTO] Automatic key generation supported │
│ [SHARED] wolfCrypt shared with SSL/TLS │
│ [FLEXIBLE] Multiple key installation methods │
│ [UPDATED] New authentication API available │
│ │
└──────────────────────────────────────────────────────┘
Recommended Approach:**
- Use ECC keys for embedded systems
- Implement key-based authentication
- Use UserAuthManager for credentials
- Enable auto-regeneration in production
- Monitor authentication attempts
- Keep NNDK updated
For the latest information and examples, refer to: